1 /* Library which manipulates firewall rules. Version $Revision$ */
2
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
11 /* (C) 1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
12 * COPYING for details).
13 * (C) 2000-2004 by the Netfilter Core Team <coreteam@netfilter.org>
14 *
15 * 2003-Jun-20: Harald Welte <laforge@netfilter.org>:
16 * - Reimplementation of chain cache to use offsets instead of entries
17 * 2003-Jun-23: Harald Welte <laforge@netfilter.org>:
18 * - performance optimization, sponsored by Astaro AG (http://www.astaro.com/)
19 * don't rebuild the chain cache after every operation, instead fix it
20 * up after a ruleset change.
21 * 2004-Aug-18: Harald Welte <laforge@netfilter.org>:
22 * - further performance work: total reimplementation of libiptc.
23 * - libiptc now has a real internal (linked-list) represntation of the
24 * ruleset and a parser/compiler from/to this internal representation
25 * - again sponsored by Astaro AG (http://www.astaro.com/)
26 *
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/)
31 */
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <stdbool.h>
37 #include <xtables.h>
38 #include <libiptc/xtcshared.h>
39
40 #include "linux_list.h"
41
42 //#define IPTC_DEBUG2 1
43
44 #ifdef IPTC_DEBUG2
45 #include <fcntl.h>
46 #define DEBUGP(x, args...) fprintf(stderr, "%s: " x, __FUNCTION__, ## args)
47 #define DEBUGP_C(x, args...) fprintf(stderr, x, ## args)
48 #else
49 #define DEBUGP(x, args...)
50 #define DEBUGP_C(x, args...)
51 #endif
52
53 #ifdef DEBUG
54 #define debug(x, args...) fprintf(stderr, x, ## args)
55 #else
56 #define debug(x, args...)
57 #endif
58
59 static void *iptc_fn = NULL;
60
61 static const char *hooknames[] = {
62 [HOOK_PRE_ROUTING] = "PREROUTING",
63 [HOOK_LOCAL_IN] = "INPUT",
64 [HOOK_FORWARD] = "FORWARD",
65 [HOOK_LOCAL_OUT] = "OUTPUT",
66 [HOOK_POST_ROUTING] = "POSTROUTING",
67 };
68
69 /* Convenience structures */
70 struct chain_head;
71 struct rule_head;
72
73 struct counter_map
74 {
75 enum {
76 COUNTER_MAP_NOMAP,
77 COUNTER_MAP_NORMAL_MAP,
78 COUNTER_MAP_ZEROED,
79 COUNTER_MAP_SET
80 } maptype;
81 unsigned int mappos;
82 };
83
84 enum iptcc_rule_type {
85 IPTCC_R_STANDARD, /* standard target (ACCEPT, ...) */
86 IPTCC_R_MODULE, /* extension module (SNAT, ...) */
87 IPTCC_R_FALLTHROUGH, /* fallthrough rule */
88 IPTCC_R_JUMP, /* jump to other chain */
89 };
90
91 struct rule_head
92 {
93 struct list_head list;
94 struct chain_head *chain;
95 struct counter_map counter_map;
96
97 unsigned int index; /* index (needed for counter_map) */
98 unsigned int offset; /* offset in rule blob */
99
100 enum iptcc_rule_type type;
101 struct chain_head *jump; /* jump target, if IPTCC_R_JUMP */
102
103 unsigned int size; /* size of entry data */
104 STRUCT_ENTRY entry[0];
105 };
106
107 struct chain_head
108 {
109 struct list_head list;
110 char name[TABLE_MAXNAMELEN];
111 unsigned int hooknum; /* hook number+1 if builtin */
112 unsigned int references; /* how many jumps reference us */
113 int verdict; /* verdict if builtin */
114
115 STRUCT_COUNTERS counters; /* per-chain counters */
116 struct counter_map counter_map;
117
118 unsigned int num_rules; /* number of rules in list */
119 struct list_head rules; /* list of rules */
120
121 unsigned int index; /* index (needed for jump resolval) */
122 unsigned int head_offset; /* offset in rule blob */
123 unsigned int foot_index; /* index (needed for counter_map) */
124 unsigned int foot_offset; /* offset in rule blob */
125 };
126
127 struct xtc_handle {
128 int sockfd;
129 int changed; /* Have changes been made? */
130
131 struct list_head chains;
132
133 struct chain_head *chain_iterator_cur;
134 struct rule_head *rule_iterator_cur;
135
136 unsigned int num_chains; /* number of user defined chains */
137
138 struct chain_head **chain_index; /* array for fast chain list access*/
139 unsigned int chain_index_sz;/* size of chain index array */
140
141 int sorted_offsets; /* if chains are received sorted from kernel,
142 * then the offsets are also sorted. Says if its
143 * possible to bsearch offsets using chain_index.
144 */
145
146 STRUCT_GETINFO info;
147 STRUCT_GET_ENTRIES *entries;
148 };
149
150 enum bsearch_type {
151 BSEARCH_NAME, /* Binary search after chain name */
152 BSEARCH_OFFSET, /* Binary search based on offset */
153 };
154
155 /* allocate a new chain head for the cache */
iptcc_alloc_chain_head(const char * name,int hooknum)156 static struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
157 {
158 struct chain_head *c = malloc(sizeof(*c));
159 if (!c)
160 return NULL;
161 memset(c, 0, sizeof(*c));
162
163 strncpy(c->name, name, TABLE_MAXNAMELEN - 1);
164 c->hooknum = hooknum;
165 INIT_LIST_HEAD(&c->rules);
166
167 return c;
168 }
169
170 /* allocate and initialize a new rule for the cache */
iptcc_alloc_rule(struct chain_head * c,unsigned int size)171 static struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int size)
172 {
173 struct rule_head *r = malloc(sizeof(*r)+size);
174 if (!r)
175 return NULL;
176 memset(r, 0, sizeof(*r));
177
178 r->chain = c;
179 r->size = size;
180
181 return r;
182 }
183
184 /* notify us that the ruleset has been modified by the user */
185 static inline void
set_changed(struct xtc_handle * h)186 set_changed(struct xtc_handle *h)
187 {
188 h->changed = 1;
189 }
190
191 /**********************************************************************
192 * iptc blob utility functions (iptcb_*)
193 **********************************************************************/
194
195 static inline int
iptcb_get_number(const STRUCT_ENTRY * i,const STRUCT_ENTRY * seek,unsigned int * pos)196 iptcb_get_number(const STRUCT_ENTRY *i,
197 const STRUCT_ENTRY *seek,
198 unsigned int *pos)
199 {
200 if (i == seek)
201 return 1;
202 (*pos)++;
203 return 0;
204 }
205
206 static inline int
iptcb_get_entry_n(STRUCT_ENTRY * i,unsigned int number,unsigned int * pos,STRUCT_ENTRY ** pe)207 iptcb_get_entry_n(STRUCT_ENTRY *i,
208 unsigned int number,
209 unsigned int *pos,
210 STRUCT_ENTRY **pe)
211 {
212 if (*pos == number) {
213 *pe = i;
214 return 1;
215 }
216 (*pos)++;
217 return 0;
218 }
219
220 static inline STRUCT_ENTRY *
iptcb_get_entry(struct xtc_handle * h,unsigned int offset)221 iptcb_get_entry(struct xtc_handle *h, unsigned int offset)
222 {
223 return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset);
224 }
225
226 static unsigned int
iptcb_entry2index(struct xtc_handle * const h,const STRUCT_ENTRY * seek)227 iptcb_entry2index(struct xtc_handle *const h, const STRUCT_ENTRY *seek)
228 {
229 unsigned int pos = 0;
230
231 if (ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
232 iptcb_get_number, seek, &pos) == 0) {
233 fprintf(stderr, "ERROR: offset %u not an entry!\n",
234 (unsigned int)((char *)seek - (char *)h->entries->entrytable));
235 abort();
236 }
237 return pos;
238 }
239
240 static inline STRUCT_ENTRY *
iptcb_offset2entry(struct xtc_handle * h,unsigned int offset)241 iptcb_offset2entry(struct xtc_handle *h, unsigned int offset)
242 {
243 return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset);
244 }
245
246
247 static inline unsigned long
iptcb_entry2offset(struct xtc_handle * const h,const STRUCT_ENTRY * e)248 iptcb_entry2offset(struct xtc_handle *const h, const STRUCT_ENTRY *e)
249 {
250 return (void *)e - (void *)h->entries->entrytable;
251 }
252
253 static inline unsigned int
iptcb_offset2index(struct xtc_handle * const h,unsigned int offset)254 iptcb_offset2index(struct xtc_handle *const h, unsigned int offset)
255 {
256 return iptcb_entry2index(h, iptcb_offset2entry(h, offset));
257 }
258
259 /* Returns 0 if not hook entry, else hooknumber + 1 */
260 static inline unsigned int
iptcb_ent_is_hook_entry(STRUCT_ENTRY * e,struct xtc_handle * h)261 iptcb_ent_is_hook_entry(STRUCT_ENTRY *e, struct xtc_handle *h)
262 {
263 unsigned int i;
264
265 for (i = 0; i < NUMHOOKS; i++) {
266 if ((h->info.valid_hooks & (1 << i))
267 && iptcb_get_entry(h, h->info.hook_entry[i]) == e)
268 return i+1;
269 }
270 return 0;
271 }
272
273
274 /**********************************************************************
275 * Chain index (cache utility) functions
276 **********************************************************************
277 * The chain index is an array with pointers into the chain list, with
278 * CHAIN_INDEX_BUCKET_LEN spacing. This facilitates the ability to
279 * speedup chain list searching, by find a more optimal starting
280 * points when searching the linked list.
281 *
282 * The starting point can be found fast by using a binary search of
283 * the chain index. Thus, reducing the previous search complexity of
284 * O(n) to O(log(n/k) + k) where k is CHAIN_INDEX_BUCKET_LEN.
285 *
286 * A nice property of the chain index, is that the "bucket" list
287 * length is max CHAIN_INDEX_BUCKET_LEN (when just build, inserts will
288 * change this). Oppose to hashing, where the "bucket" list length can
289 * vary a lot.
290 */
291 #ifndef CHAIN_INDEX_BUCKET_LEN
292 #define CHAIN_INDEX_BUCKET_LEN 40
293 #endif
294
295 /* Another nice property of the chain index is that inserting/creating
296 * chains in chain list don't change the correctness of the chain
297 * index, it only causes longer lists in the buckets.
298 *
299 * To mitigate the performance penalty of longer bucket lists and the
300 * penalty of rebuilding, the chain index is rebuild only when
301 * CHAIN_INDEX_INSERT_MAX chains has been added.
302 */
303 #ifndef CHAIN_INDEX_INSERT_MAX
304 #define CHAIN_INDEX_INSERT_MAX 355
305 #endif
306
307 static inline unsigned int iptcc_is_builtin(struct chain_head *c);
308
309 /* Use binary search in the chain index array, to find a chain_head
310 * pointer closest to the place of the searched name element.
311 *
312 * Notes that, binary search (obviously) requires that the chain list
313 * is sorted by name.
314 *
315 * The not so obvious: The chain index array, is actually both sorted
316 * by name and offset, at the same time!. This is only true because,
317 * chain are stored sorted in the kernel (as we pushed it in sorted).
318 *
319 */
320 static struct list_head *
__iptcc_bsearch_chain_index(const char * name,unsigned int offset,unsigned int * idx,struct xtc_handle * handle,enum bsearch_type type)321 __iptcc_bsearch_chain_index(const char *name, unsigned int offset,
322 unsigned int *idx, struct xtc_handle *handle,
323 enum bsearch_type type)
324 {
325 unsigned int pos, end;
326 int res;
327
328 struct list_head *list_pos;
329 list_pos=&handle->chains;
330
331 /* Check for empty array, e.g. no user defined chains */
332 if (handle->chain_index_sz == 0) {
333 debug("WARNING: handle->chain_index_sz == 0\n");
334 return list_pos;
335 }
336
337 /* Init */
338 end = handle->chain_index_sz;
339 pos = end / 2;
340
341 debug("bsearch Find chain:%s (pos:%d end:%d) (offset:%d)\n",
342 name, pos, end, offset);
343
344 /* Loop */
345 loop:
346 if (!handle->chain_index[pos]) {
347 fprintf(stderr, "ERROR: NULL pointer chain_index[%d]\n", pos);
348 return &handle->chains; /* Be safe, return orig start pos */
349 }
350
351 debug("bsearch Index[%d] name:%s ",
352 pos, handle->chain_index[pos]->name);
353
354 /* Support for different compare functions */
355 switch (type) {
356 case BSEARCH_NAME:
357 res = strcmp(name, handle->chain_index[pos]->name);
358 break;
359 case BSEARCH_OFFSET:
360 debug("head_offset:[%d] foot_offset:[%d] ",
361 handle->chain_index[pos]->head_offset,
362 handle->chain_index[pos]->foot_offset);
363 res = offset - handle->chain_index[pos]->head_offset;
364 break;
365 default:
366 fprintf(stderr, "ERROR: %d not a valid bsearch type\n",
367 type);
368 abort();
369 break;
370 }
371 debug("res:%d ", res);
372
373
374 list_pos = &handle->chain_index[pos]->list;
375 *idx = pos;
376
377 if (res == 0) { /* Found element, by direct hit */
378 debug("[found] Direct hit pos:%d end:%d\n", pos, end);
379 return list_pos;
380 } else if (res < 0) { /* Too far, jump back */
381 end = pos;
382 pos = pos / 2;
383
384 /* Exit case: First element of array */
385 if (end == 0) {
386 debug("[found] Reached first array elem (end%d)\n",end);
387 return list_pos;
388 }
389 debug("jump back to pos:%d (end:%d)\n", pos, end);
390 goto loop;
391 } else { /* res > 0; Not far enough, jump forward */
392
393 /* Exit case: Last element of array */
394 if (pos == handle->chain_index_sz-1) {
395 debug("[found] Last array elem (end:%d)\n", end);
396 return list_pos;
397 }
398
399 /* Exit case: Next index less, thus elem in this list section */
400 switch (type) {
401 case BSEARCH_NAME:
402 res = strcmp(name, handle->chain_index[pos+1]->name);
403 break;
404 case BSEARCH_OFFSET:
405 res = offset - handle->chain_index[pos+1]->head_offset;
406 break;
407 }
408
409 if (res < 0) {
410 debug("[found] closest list (end:%d)\n", end);
411 return list_pos;
412 }
413
414 pos = (pos+end)/2;
415 debug("jump forward to pos:%d (end:%d)\n", pos, end);
416 goto loop;
417 }
418 }
419
420 /* Wrapper for string chain name based bsearch */
421 static struct list_head *
iptcc_bsearch_chain_index(const char * name,unsigned int * idx,struct xtc_handle * handle)422 iptcc_bsearch_chain_index(const char *name, unsigned int *idx,
423 struct xtc_handle *handle)
424 {
425 return __iptcc_bsearch_chain_index(name, 0, idx, handle, BSEARCH_NAME);
426 }
427
428
429 /* Wrapper for offset chain based bsearch */
430 static struct list_head *
iptcc_bsearch_chain_offset(unsigned int offset,unsigned int * idx,struct xtc_handle * handle)431 iptcc_bsearch_chain_offset(unsigned int offset, unsigned int *idx,
432 struct xtc_handle *handle)
433 {
434 struct list_head *pos;
435
436 /* If chains were not received sorted from kernel, then the
437 * offset bsearch is not possible.
438 */
439 if (!handle->sorted_offsets)
440 pos = handle->chains.next;
441 else
442 pos = __iptcc_bsearch_chain_index(NULL, offset, idx, handle,
443 BSEARCH_OFFSET);
444 return pos;
445 }
446
447
448 #ifdef DEBUG
449 /* Trivial linear search of chain index. Function used for verifying
450 the output of bsearch function */
451 static struct list_head *
iptcc_linearly_search_chain_index(const char * name,struct xtc_handle * handle)452 iptcc_linearly_search_chain_index(const char *name, struct xtc_handle *handle)
453 {
454 unsigned int i=0;
455 int res=0;
456
457 struct list_head *list_pos;
458 list_pos = &handle->chains;
459
460 if (handle->chain_index_sz)
461 list_pos = &handle->chain_index[0]->list;
462
463 /* Linearly walk of chain index array */
464
465 for (i=0; i < handle->chain_index_sz; i++) {
466 if (handle->chain_index[i]) {
467 res = strcmp(handle->chain_index[i]->name, name);
468 if (res > 0)
469 break; // One step too far
470 list_pos = &handle->chain_index[i]->list;
471 if (res == 0)
472 break; // Direct hit
473 }
474 }
475
476 return list_pos;
477 }
478 #endif
479
iptcc_chain_index_alloc(struct xtc_handle * h)480 static int iptcc_chain_index_alloc(struct xtc_handle *h)
481 {
482 unsigned int list_length = CHAIN_INDEX_BUCKET_LEN;
483 unsigned int array_elems;
484 unsigned int array_mem;
485
486 /* Allocate memory for the chain index array */
487 array_elems = (h->num_chains / list_length) +
488 (h->num_chains % list_length ? 1 : 0);
489 array_mem = sizeof(h->chain_index) * array_elems;
490
491 debug("Alloc Chain index, elems:%d mem:%d bytes\n",
492 array_elems, array_mem);
493
494 h->chain_index = malloc(array_mem);
495 if (h->chain_index == NULL && array_mem > 0) {
496 h->chain_index_sz = 0;
497 return -ENOMEM;
498 }
499 memset(h->chain_index, 0, array_mem);
500 h->chain_index_sz = array_elems;
501
502 return 1;
503 }
504
iptcc_chain_index_free(struct xtc_handle * h)505 static void iptcc_chain_index_free(struct xtc_handle *h)
506 {
507 h->chain_index_sz = 0;
508 free(h->chain_index);
509 }
510
511
512 #ifdef DEBUG
iptcc_chain_index_dump(struct xtc_handle * h)513 static void iptcc_chain_index_dump(struct xtc_handle *h)
514 {
515 unsigned int i = 0;
516
517 /* Dump: contents of chain index array */
518 for (i=0; i < h->chain_index_sz; i++) {
519 if (h->chain_index[i]) {
520 fprintf(stderr, "Chain index[%d].name: %s\n",
521 i, h->chain_index[i]->name);
522 }
523 }
524 }
525 #endif
526
527 /* Build the chain index */
iptcc_chain_index_build(struct xtc_handle * h)528 static int iptcc_chain_index_build(struct xtc_handle *h)
529 {
530 unsigned int list_length = CHAIN_INDEX_BUCKET_LEN;
531 unsigned int chains = 0;
532 unsigned int cindex = 0;
533 struct chain_head *c;
534
535 /* Build up the chain index array here */
536 debug("Building chain index\n");
537
538 debug("Number of user defined chains:%d bucket_sz:%d array_sz:%d\n",
539 h->num_chains, list_length, h->chain_index_sz);
540
541 if (h->chain_index_sz == 0)
542 return 0;
543
544 list_for_each_entry(c, &h->chains, list) {
545
546 /* Issue: The index array needs to start after the
547 * builtin chains, as they are not sorted */
548 if (!iptcc_is_builtin(c)) {
549 cindex=chains / list_length;
550
551 /* Safe guard, break out on array limit, this
552 * is useful if chains are added and array is
553 * rebuild, without realloc of memory. */
554 if (cindex >= h->chain_index_sz)
555 break;
556
557 if ((chains % list_length)== 0) {
558 debug("\nIndex[%d] Chains:", cindex);
559 h->chain_index[cindex] = c;
560 }
561 chains++;
562 }
563 debug("%s, ", c->name);
564 }
565 debug("\n");
566
567 return 1;
568 }
569
iptcc_chain_index_rebuild(struct xtc_handle * h)570 static int iptcc_chain_index_rebuild(struct xtc_handle *h)
571 {
572 debug("REBUILD chain index array\n");
573 iptcc_chain_index_free(h);
574 if ((iptcc_chain_index_alloc(h)) < 0)
575 return -ENOMEM;
576 iptcc_chain_index_build(h);
577 return 1;
578 }
579
580 /* Delete chain (pointer) from index array. Removing an element from
581 * the chain list only affects the chain index array, if the chain
582 * index points-to/uses that list pointer.
583 *
584 * There are different strategies, the simple and safe is to rebuild
585 * the chain index every time. The more advanced is to update the
586 * array index to point to the next element, but that requires some
587 * house keeping and boundary checks. The advanced is implemented, as
588 * the simple approach behaves badly when all chains are deleted
589 * because list_for_each processing will always hit the first chain
590 * index, thus causing a rebuild for every chain.
591 */
iptcc_chain_index_delete_chain(struct chain_head * c,struct xtc_handle * h)592 static int iptcc_chain_index_delete_chain(struct chain_head *c, struct xtc_handle *h)
593 {
594 struct list_head *index_ptr, *next;
595 struct chain_head *c2;
596 unsigned int idx, idx2;
597
598 index_ptr = iptcc_bsearch_chain_index(c->name, &idx, h);
599
600 debug("Del chain[%s] c->list:%p index_ptr:%p\n",
601 c->name, &c->list, index_ptr);
602
603 /* Save the next pointer */
604 next = c->list.next;
605 list_del(&c->list);
606
607 if (index_ptr == &c->list) { /* Chain used as index ptr */
608
609 /* See if its possible to avoid a rebuild, by shifting
610 * to next pointer. Its possible if the next pointer
611 * is located in the same index bucket.
612 */
613 c2 = list_entry(next, struct chain_head, list);
614 iptcc_bsearch_chain_index(c2->name, &idx2, h);
615 if (idx != idx2) {
616 /* Rebuild needed */
617 return iptcc_chain_index_rebuild(h);
618 } else {
619 /* Avoiding rebuild */
620 debug("Update cindex[%d] with next ptr name:[%s]\n",
621 idx, c2->name);
622 h->chain_index[idx]=c2;
623 return 0;
624 }
625 }
626 return 0;
627 }
628
629
630 /**********************************************************************
631 * iptc cache utility functions (iptcc_*)
632 **********************************************************************/
633
634 /* Is the given chain builtin (1) or user-defined (0) */
iptcc_is_builtin(struct chain_head * c)635 static inline unsigned int iptcc_is_builtin(struct chain_head *c)
636 {
637 return (c->hooknum ? 1 : 0);
638 }
639
640 /* Get a specific rule within a chain */
iptcc_get_rule_num(struct chain_head * c,unsigned int rulenum)641 static struct rule_head *iptcc_get_rule_num(struct chain_head *c,
642 unsigned int rulenum)
643 {
644 struct rule_head *r;
645 unsigned int num = 0;
646
647 list_for_each_entry(r, &c->rules, list) {
648 num++;
649 if (num == rulenum)
650 return r;
651 }
652 return NULL;
653 }
654
655 /* Get a specific rule within a chain backwards */
iptcc_get_rule_num_reverse(struct chain_head * c,unsigned int rulenum)656 static struct rule_head *iptcc_get_rule_num_reverse(struct chain_head *c,
657 unsigned int rulenum)
658 {
659 struct rule_head *r;
660 unsigned int num = 0;
661
662 list_for_each_entry_reverse(r, &c->rules, list) {
663 num++;
664 if (num == rulenum)
665 return r;
666 }
667 return NULL;
668 }
669
670 /* Returns chain head if found, otherwise NULL. */
671 static struct chain_head *
iptcc_find_chain_by_offset(struct xtc_handle * handle,unsigned int offset)672 iptcc_find_chain_by_offset(struct xtc_handle *handle, unsigned int offset)
673 {
674 struct list_head *pos;
675 struct list_head *list_start_pos;
676 unsigned int i;
677
678 if (list_empty(&handle->chains))
679 return NULL;
680
681 /* Find a smart place to start the search */
682 list_start_pos = iptcc_bsearch_chain_offset(offset, &i, handle);
683
684 /* Note that iptcc_bsearch_chain_offset() skips builtin
685 * chains, but this function is only used for finding jump
686 * targets, and a buildin chain is not a valid jump target */
687
688 debug("Offset:[%u] starting search at index:[%u]\n", offset, i);
689 // list_for_each(pos, &handle->chains) {
690 list_for_each(pos, list_start_pos->prev) {
691 struct chain_head *c = list_entry(pos, struct chain_head, list);
692 debug(".");
693 if (offset >= c->head_offset && offset <= c->foot_offset) {
694 debug("Offset search found chain:[%s]\n", c->name);
695 return c;
696 }
697 }
698
699 return NULL;
700 }
701
702 /* Returns chain head if found, otherwise NULL. */
703 static struct chain_head *
iptcc_find_label(const char * name,struct xtc_handle * handle)704 iptcc_find_label(const char *name, struct xtc_handle *handle)
705 {
706 struct list_head *pos;
707 struct list_head *list_start_pos;
708 unsigned int i=0;
709 int res;
710
711 if (list_empty(&handle->chains))
712 return NULL;
713
714 /* First look at builtin chains */
715 list_for_each(pos, &handle->chains) {
716 struct chain_head *c = list_entry(pos, struct chain_head, list);
717 if (!iptcc_is_builtin(c))
718 break;
719 if (!strcmp(c->name, name))
720 return c;
721 }
722
723 /* Find a smart place to start the search via chain index */
724 //list_start_pos = iptcc_linearly_search_chain_index(name, handle);
725 list_start_pos = iptcc_bsearch_chain_index(name, &i, handle);
726
727 /* Handel if bsearch bails out early */
728 if (list_start_pos == &handle->chains) {
729 list_start_pos = pos;
730 }
731 #ifdef DEBUG
732 else {
733 /* Verify result of bsearch against linearly index search */
734 struct list_head *test_pos;
735 struct chain_head *test_c, *tmp_c;
736 test_pos = iptcc_linearly_search_chain_index(name, handle);
737 if (list_start_pos != test_pos) {
738 debug("BUG in chain_index search\n");
739 test_c=list_entry(test_pos, struct chain_head,list);
740 tmp_c =list_entry(list_start_pos,struct chain_head,list);
741 debug("Verify search found:\n");
742 debug(" Chain:%s\n", test_c->name);
743 debug("BSearch found:\n");
744 debug(" Chain:%s\n", tmp_c->name);
745 exit(42);
746 }
747 }
748 #endif
749
750 /* Initial/special case, no user defined chains */
751 if (handle->num_chains == 0)
752 return NULL;
753
754 /* Start searching through the chain list */
755 list_for_each(pos, list_start_pos->prev) {
756 struct chain_head *c = list_entry(pos, struct chain_head, list);
757 res = strcmp(c->name, name);
758 debug("List search name:%s == %s res:%d\n", name, c->name, res);
759 if (res==0)
760 return c;
761
762 /* We can stop earlier as we know list is sorted */
763 if (res>0 && !iptcc_is_builtin(c)) { /* Walked too far*/
764 debug(" Not in list, walked too far, sorted list\n");
765 return NULL;
766 }
767
768 /* Stop on wrap around, if list head is reached */
769 if (pos == &handle->chains) {
770 debug("Stop, list head reached\n");
771 return NULL;
772 }
773 }
774
775 debug("List search NOT found name:%s\n", name);
776 return NULL;
777 }
778
779 /* called when rule is to be removed from cache */
iptcc_delete_rule(struct rule_head * r)780 static void iptcc_delete_rule(struct rule_head *r)
781 {
782 DEBUGP("deleting rule %p (offset %u)\n", r, r->offset);
783 /* clean up reference count of called chain */
784 if (r->type == IPTCC_R_JUMP
785 && r->jump)
786 r->jump->references--;
787
788 list_del(&r->list);
789 free(r);
790 }
791
792
793 /**********************************************************************
794 * RULESET PARSER (blob -> cache)
795 **********************************************************************/
796
797 /* Delete policy rule of previous chain, since cache doesn't contain
798 * chain policy rules.
799 * WARNING: This function has ugly design and relies on a lot of context, only
800 * to be called from specific places within the parser */
__iptcc_p_del_policy(struct xtc_handle * h,unsigned int num)801 static int __iptcc_p_del_policy(struct xtc_handle *h, unsigned int num)
802 {
803 const unsigned char *data;
804
805 if (h->chain_iterator_cur) {
806 /* policy rule is last rule */
807 struct rule_head *pr = (struct rule_head *)
808 h->chain_iterator_cur->rules.prev;
809
810 /* save verdict */
811 data = GET_TARGET(pr->entry)->data;
812 h->chain_iterator_cur->verdict = *(const int *)data;
813
814 /* save counter and counter_map information */
815 h->chain_iterator_cur->counter_map.maptype =
816 COUNTER_MAP_ZEROED;
817 h->chain_iterator_cur->counter_map.mappos = num-1;
818 memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters,
819 sizeof(h->chain_iterator_cur->counters));
820
821 /* foot_offset points to verdict rule */
822 h->chain_iterator_cur->foot_index = num;
823 h->chain_iterator_cur->foot_offset = pr->offset;
824
825 /* delete rule from cache */
826 iptcc_delete_rule(pr);
827 h->chain_iterator_cur->num_rules--;
828
829 return 1;
830 }
831 return 0;
832 }
833
834 /* alphabetically insert a chain into the list */
iptc_insert_chain(struct xtc_handle * h,struct chain_head * c)835 static void iptc_insert_chain(struct xtc_handle *h, struct chain_head *c)
836 {
837 struct chain_head *tmp;
838 struct list_head *list_start_pos;
839 unsigned int i=1;
840
841 /* Find a smart place to start the insert search */
842 list_start_pos = iptcc_bsearch_chain_index(c->name, &i, h);
843
844 /* Handle the case, where chain.name is smaller than index[0] */
845 if (i==0 && strcmp(c->name, h->chain_index[0]->name) <= 0) {
846 h->chain_index[0] = c; /* Update chain index head */
847 list_start_pos = h->chains.next;
848 debug("Update chain_index[0] with %s\n", c->name);
849 }
850
851 /* Handel if bsearch bails out early */
852 if (list_start_pos == &h->chains) {
853 list_start_pos = h->chains.next;
854 }
855
856 /* sort only user defined chains */
857 if (!c->hooknum) {
858 list_for_each_entry(tmp, list_start_pos->prev, list) {
859 if (!tmp->hooknum && strcmp(c->name, tmp->name) <= 0) {
860 list_add(&c->list, tmp->list.prev);
861 return;
862 }
863
864 /* Stop if list head is reached */
865 if (&tmp->list == &h->chains) {
866 debug("Insert, list head reached add to tail\n");
867 break;
868 }
869 }
870 }
871
872 /* survived till end of list: add at tail */
873 list_add_tail(&c->list, &h->chains);
874 }
875
876 /* Another ugly helper function split out of cache_add_entry to make it less
877 * spaghetti code */
__iptcc_p_add_chain(struct xtc_handle * h,struct chain_head * c,unsigned int offset,unsigned int * num)878 static void __iptcc_p_add_chain(struct xtc_handle *h, struct chain_head *c,
879 unsigned int offset, unsigned int *num)
880 {
881 struct list_head *tail = h->chains.prev;
882 struct chain_head *ctail;
883
884 __iptcc_p_del_policy(h, *num);
885
886 c->head_offset = offset;
887 c->index = *num;
888
889 /* Chains from kernel are already sorted, as they are inserted
890 * sorted. But there exists an issue when shifting to 1.4.0
891 * from an older version, as old versions allow last created
892 * chain to be unsorted.
893 */
894 if (iptcc_is_builtin(c)) /* Only user defined chains are sorted*/
895 list_add_tail(&c->list, &h->chains);
896 else {
897 ctail = list_entry(tail, struct chain_head, list);
898
899 if (strcmp(c->name, ctail->name) > 0 ||
900 iptcc_is_builtin(ctail))
901 list_add_tail(&c->list, &h->chains);/* Already sorted*/
902 else {
903 iptc_insert_chain(h, c);/* Was not sorted */
904
905 /* Notice, if chains were not received sorted
906 * from kernel, then an offset bsearch is no
907 * longer valid.
908 */
909 h->sorted_offsets = 0;
910
911 debug("NOTICE: chain:[%s] was NOT sorted(ctail:%s)\n",
912 c->name, ctail->name);
913 }
914 }
915
916 h->chain_iterator_cur = c;
917 }
918
919 /* main parser function: add an entry from the blob to the cache */
cache_add_entry(STRUCT_ENTRY * e,struct xtc_handle * h,STRUCT_ENTRY ** prev,unsigned int * num)920 static int cache_add_entry(STRUCT_ENTRY *e,
921 struct xtc_handle *h,
922 STRUCT_ENTRY **prev,
923 unsigned int *num)
924 {
925 unsigned int builtin;
926 unsigned int offset = (char *)e - (char *)h->entries->entrytable;
927
928 DEBUGP("entering...");
929
930 /* Last entry ("policy rule"). End it.*/
931 if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) {
932 /* This is the ERROR node at the end of the chain */
933 DEBUGP_C("%u:%u: end of table:\n", *num, offset);
934
935 __iptcc_p_del_policy(h, *num);
936
937 h->chain_iterator_cur = NULL;
938 goto out_inc;
939 }
940
941 /* We know this is the start of a new chain if it's an ERROR
942 * target, or a hook entry point */
943
944 if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
945 struct chain_head *c =
946 iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0);
947 DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset,
948 (char *)c->name, c);
949 if (!c) {
950 errno = -ENOMEM;
951 return -1;
952 }
953 h->num_chains++; /* New user defined chain */
954
955 __iptcc_p_add_chain(h, c, offset, num);
956
957 } else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) {
958 struct chain_head *c =
959 iptcc_alloc_chain_head((char *)hooknames[builtin-1],
960 builtin);
961 DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
962 *num, offset, c, &c->rules);
963 if (!c) {
964 errno = -ENOMEM;
965 return -1;
966 }
967
968 c->hooknum = builtin;
969
970 __iptcc_p_add_chain(h, c, offset, num);
971
972 /* FIXME: this is ugly. */
973 goto new_rule;
974 } else {
975 /* has to be normal rule */
976 struct rule_head *r;
977 new_rule:
978
979 if (!(r = iptcc_alloc_rule(h->chain_iterator_cur,
980 e->next_offset))) {
981 errno = ENOMEM;
982 return -1;
983 }
984 DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
985
986 r->index = *num;
987 r->offset = offset;
988 memcpy(r->entry, e, e->next_offset);
989 r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP;
990 r->counter_map.mappos = r->index;
991
992 /* handling of jumps, etc. */
993 if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) {
994 STRUCT_STANDARD_TARGET *t;
995
996 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
997 if (t->target.u.target_size
998 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
999 errno = EINVAL;
1000 free(r);
1001 return -1;
1002 }
1003
1004 if (t->verdict < 0) {
1005 DEBUGP_C("standard, verdict=%d\n", t->verdict);
1006 r->type = IPTCC_R_STANDARD;
1007 } else if (t->verdict == r->offset+e->next_offset) {
1008 DEBUGP_C("fallthrough\n");
1009 r->type = IPTCC_R_FALLTHROUGH;
1010 } else {
1011 DEBUGP_C("jump, target=%u\n", t->verdict);
1012 r->type = IPTCC_R_JUMP;
1013 /* Jump target fixup has to be deferred
1014 * until second pass, since we migh not
1015 * yet have parsed the target */
1016 }
1017 } else {
1018 DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name);
1019 r->type = IPTCC_R_MODULE;
1020 }
1021
1022 list_add_tail(&r->list, &h->chain_iterator_cur->rules);
1023 h->chain_iterator_cur->num_rules++;
1024 }
1025 out_inc:
1026 (*num)++;
1027 return 0;
1028 }
1029
1030
1031 /* parse an iptables blob into it's pieces */
parse_table(struct xtc_handle * h)1032 static int parse_table(struct xtc_handle *h)
1033 {
1034 STRUCT_ENTRY *prev;
1035 unsigned int num = 0;
1036 struct chain_head *c;
1037
1038 /* Assume that chains offsets are sorted, this verified during
1039 parsing of ruleset (in __iptcc_p_add_chain())*/
1040 h->sorted_offsets = 1;
1041
1042 /* First pass: over ruleset blob */
1043 ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
1044 cache_add_entry, h, &prev, &num);
1045
1046 /* Build the chain index, used for chain list search speedup */
1047 if ((iptcc_chain_index_alloc(h)) < 0)
1048 return -ENOMEM;
1049 iptcc_chain_index_build(h);
1050
1051 /* Second pass: fixup parsed data from first pass */
1052 list_for_each_entry(c, &h->chains, list) {
1053 struct rule_head *r;
1054 list_for_each_entry(r, &c->rules, list) {
1055 struct chain_head *lc;
1056 STRUCT_STANDARD_TARGET *t;
1057
1058 if (r->type != IPTCC_R_JUMP)
1059 continue;
1060
1061 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
1062 lc = iptcc_find_chain_by_offset(h, t->verdict);
1063 if (!lc)
1064 return -1;
1065 r->jump = lc;
1066 lc->references++;
1067 }
1068 }
1069
1070 return 1;
1071 }
1072
1073
1074 /**********************************************************************
1075 * RULESET COMPILATION (cache -> blob)
1076 **********************************************************************/
1077
1078 /* Convenience structures */
1079 struct iptcb_chain_start{
1080 STRUCT_ENTRY e;
1081 struct xt_error_target name;
1082 };
1083 #define IPTCB_CHAIN_START_SIZE (sizeof(STRUCT_ENTRY) + \
1084 ALIGN(sizeof(struct xt_error_target)))
1085
1086 struct iptcb_chain_foot {
1087 STRUCT_ENTRY e;
1088 STRUCT_STANDARD_TARGET target;
1089 };
1090 #define IPTCB_CHAIN_FOOT_SIZE (sizeof(STRUCT_ENTRY) + \
1091 ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
1092
1093 struct iptcb_chain_error {
1094 STRUCT_ENTRY entry;
1095 struct xt_error_target target;
1096 };
1097 #define IPTCB_CHAIN_ERROR_SIZE (sizeof(STRUCT_ENTRY) + \
1098 ALIGN(sizeof(struct xt_error_target)))
1099
1100
1101
1102 /* compile rule from cache into blob */
iptcc_compile_rule(struct xtc_handle * h,STRUCT_REPLACE * repl,struct rule_head * r)1103 static inline int iptcc_compile_rule (struct xtc_handle *h, STRUCT_REPLACE *repl, struct rule_head *r)
1104 {
1105 /* handle jumps */
1106 if (r->type == IPTCC_R_JUMP) {
1107 STRUCT_STANDARD_TARGET *t;
1108 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
1109 /* memset for memcmp convenience on delete/replace */
1110 memset(t->target.u.user.name, 0, XT_EXTENSION_MAXNAMELEN);
1111 strcpy(t->target.u.user.name, STANDARD_TARGET);
1112 t->target.u.user.revision = 0;
1113 /* Jumps can only happen to builtin chains, so we
1114 * can safely assume that they always have a header */
1115 t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE;
1116 } else if (r->type == IPTCC_R_FALLTHROUGH) {
1117 STRUCT_STANDARD_TARGET *t;
1118 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
1119 t->verdict = r->offset + r->size;
1120 }
1121
1122 /* copy entry from cache to blob */
1123 memcpy((char *)repl->entries+r->offset, r->entry, r->size);
1124
1125 return 1;
1126 }
1127
1128 /* compile chain from cache into blob */
iptcc_compile_chain(struct xtc_handle * h,STRUCT_REPLACE * repl,struct chain_head * c)1129 static int iptcc_compile_chain(struct xtc_handle *h, STRUCT_REPLACE *repl, struct chain_head *c)
1130 {
1131 int ret;
1132 struct rule_head *r;
1133 struct iptcb_chain_start *head;
1134 struct iptcb_chain_foot *foot;
1135
1136 /* only user-defined chains have heaer */
1137 if (!iptcc_is_builtin(c)) {
1138 /* put chain header in place */
1139 head = (void *)repl->entries + c->head_offset;
1140 head->e.target_offset = sizeof(STRUCT_ENTRY);
1141 head->e.next_offset = IPTCB_CHAIN_START_SIZE;
1142 strcpy(head->name.target.u.user.name, ERROR_TARGET);
1143 head->name.target.u.target_size =
1144 ALIGN(sizeof(struct xt_error_target));
1145 strncpy(head->name.errorname, c->name, XT_FUNCTION_MAXNAMELEN);
1146 head->name.errorname[XT_FUNCTION_MAXNAMELEN - 1] = '\0';
1147 } else {
1148 repl->hook_entry[c->hooknum-1] = c->head_offset;
1149 repl->underflow[c->hooknum-1] = c->foot_offset;
1150 }
1151
1152 /* iterate over rules */
1153 list_for_each_entry(r, &c->rules, list) {
1154 ret = iptcc_compile_rule(h, repl, r);
1155 if (ret < 0)
1156 return ret;
1157 }
1158
1159 /* put chain footer in place */
1160 foot = (void *)repl->entries + c->foot_offset;
1161 foot->e.target_offset = sizeof(STRUCT_ENTRY);
1162 foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE;
1163 strcpy(foot->target.target.u.user.name, STANDARD_TARGET);
1164 foot->target.target.u.target_size =
1165 ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1166 /* builtin targets have verdict, others return */
1167 if (iptcc_is_builtin(c))
1168 foot->target.verdict = c->verdict;
1169 else
1170 foot->target.verdict = RETURN;
1171 /* set policy-counters */
1172 foot->e.counters = c->counters;
1173
1174 return 0;
1175 }
1176
1177 /* calculate offset and number for every rule in the cache */
iptcc_compile_chain_offsets(struct xtc_handle * h,struct chain_head * c,unsigned int * offset,unsigned int * num)1178 static int iptcc_compile_chain_offsets(struct xtc_handle *h, struct chain_head *c,
1179 unsigned int *offset, unsigned int *num)
1180 {
1181 struct rule_head *r;
1182
1183 c->head_offset = *offset;
1184 DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset);
1185
1186 if (!iptcc_is_builtin(c)) {
1187 /* Chain has header */
1188 *offset += sizeof(STRUCT_ENTRY)
1189 + ALIGN(sizeof(struct xt_error_target));
1190 (*num)++;
1191 }
1192
1193 list_for_each_entry(r, &c->rules, list) {
1194 DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num);
1195 r->offset = *offset;
1196 r->index = *num;
1197 *offset += r->size;
1198 (*num)++;
1199 }
1200
1201 DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num,
1202 *offset, *num);
1203 c->foot_offset = *offset;
1204 c->foot_index = *num;
1205 *offset += sizeof(STRUCT_ENTRY)
1206 + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1207 (*num)++;
1208
1209 return 1;
1210 }
1211
1212 /* put the pieces back together again */
iptcc_compile_table_prep(struct xtc_handle * h,unsigned int * size)1213 static int iptcc_compile_table_prep(struct xtc_handle *h, unsigned int *size)
1214 {
1215 struct chain_head *c;
1216 unsigned int offset = 0, num = 0;
1217 int ret = 0;
1218
1219 /* First pass: calculate offset for every rule */
1220 list_for_each_entry(c, &h->chains, list) {
1221 ret = iptcc_compile_chain_offsets(h, c, &offset, &num);
1222 if (ret < 0)
1223 return ret;
1224 }
1225
1226 /* Append one error rule at end of chain */
1227 num++;
1228 offset += sizeof(STRUCT_ENTRY)
1229 + ALIGN(sizeof(struct xt_error_target));
1230
1231 /* ruleset size is now in offset */
1232 *size = offset;
1233 return num;
1234 }
1235
iptcc_compile_table(struct xtc_handle * h,STRUCT_REPLACE * repl)1236 static int iptcc_compile_table(struct xtc_handle *h, STRUCT_REPLACE *repl)
1237 {
1238 struct chain_head *c;
1239 struct iptcb_chain_error *error;
1240
1241 /* Second pass: copy from cache to offsets, fill in jumps */
1242 list_for_each_entry(c, &h->chains, list) {
1243 int ret = iptcc_compile_chain(h, repl, c);
1244 if (ret < 0)
1245 return ret;
1246 }
1247
1248 /* Append error rule at end of chain */
1249 error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE;
1250 error->entry.target_offset = sizeof(STRUCT_ENTRY);
1251 error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE;
1252 error->target.target.u.user.target_size =
1253 ALIGN(sizeof(struct xt_error_target));
1254 strcpy((char *)&error->target.target.u.user.name, ERROR_TARGET);
1255 strcpy((char *)&error->target.errorname, "ERROR");
1256
1257 return 1;
1258 }
1259
1260 /**********************************************************************
1261 * EXTERNAL API (operates on cache only)
1262 **********************************************************************/
1263
1264 /* Allocate handle of given size */
1265 static struct xtc_handle *
alloc_handle(STRUCT_GETINFO * infop)1266 alloc_handle(STRUCT_GETINFO *infop)
1267 {
1268 struct xtc_handle *h;
1269
1270 h = malloc(sizeof(*h));
1271 if (!h) {
1272 errno = ENOMEM;
1273 return NULL;
1274 }
1275 memset(h, 0, sizeof(*h));
1276 INIT_LIST_HEAD(&h->chains);
1277 strcpy(h->info.name, infop->name);
1278
1279 h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + infop->size);
1280 if (!h->entries)
1281 goto out_free_handle;
1282
1283 strcpy(h->entries->name, infop->name);
1284 h->entries->size = infop->size;
1285
1286 return h;
1287
1288 out_free_handle:
1289 free(h);
1290
1291 return NULL;
1292 }
1293
1294
1295 struct xtc_handle *
TC_INIT(const char * tablename)1296 TC_INIT(const char *tablename)
1297 {
1298 struct xtc_handle *h;
1299 STRUCT_GETINFO info;
1300 unsigned int tmp;
1301 socklen_t s;
1302 int sockfd;
1303
1304 retry:
1305 iptc_fn = TC_INIT;
1306
1307 if (strlen(tablename) >= TABLE_MAXNAMELEN) {
1308 errno = EINVAL;
1309 return NULL;
1310 }
1311
1312 sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
1313 if (sockfd < 0)
1314 return NULL;
1315
1316 if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
1317 fprintf(stderr, "Could not set close on exec: %s\n",
1318 strerror(errno));
1319 abort();
1320 }
1321
1322 s = sizeof(info);
1323
1324 strcpy(info.name, tablename);
1325 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) {
1326 close(sockfd);
1327 return NULL;
1328 }
1329
1330 DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
1331 info.valid_hooks, info.num_entries, info.size);
1332
1333 h = alloc_handle(&info);
1334 if (h == NULL) {
1335 close(sockfd);
1336 return NULL;
1337 }
1338
1339 /* Initialize current state */
1340 h->sockfd = sockfd;
1341 h->info = info;
1342
1343 h->entries->size = h->info.size;
1344
1345 tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
1346
1347 if (getsockopt(h->sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
1348 &tmp) < 0)
1349 goto error;
1350
1351 #ifdef IPTC_DEBUG2
1352 {
1353 int fd = open("/tmp/libiptc-so_get_entries.blob",
1354 O_CREAT|O_WRONLY, 0644);
1355 if (fd >= 0) {
1356 write(fd, h->entries, tmp);
1357 close(fd);
1358 }
1359 }
1360 #endif
1361
1362 if (parse_table(h) < 0)
1363 goto error;
1364
1365 return h;
1366 error:
1367 TC_FREE(h);
1368 /* A different process changed the ruleset size, retry */
1369 if (errno == EAGAIN)
1370 goto retry;
1371 return NULL;
1372 }
1373
1374 void
TC_FREE(struct xtc_handle * h)1375 TC_FREE(struct xtc_handle *h)
1376 {
1377 struct chain_head *c, *tmp;
1378
1379 iptc_fn = TC_FREE;
1380 close(h->sockfd);
1381
1382 list_for_each_entry_safe(c, tmp, &h->chains, list) {
1383 struct rule_head *r, *rtmp;
1384
1385 list_for_each_entry_safe(r, rtmp, &c->rules, list) {
1386 free(r);
1387 }
1388
1389 free(c);
1390 }
1391
1392 iptcc_chain_index_free(h);
1393
1394 free(h->entries);
1395 free(h);
1396 }
1397
1398 static inline int
print_match(const STRUCT_ENTRY_MATCH * m)1399 print_match(const STRUCT_ENTRY_MATCH *m)
1400 {
1401 printf("Match name: `%s'\n", m->u.user.name);
1402 return 0;
1403 }
1404
1405 static int dump_entry(STRUCT_ENTRY *e, struct xtc_handle *const handle);
1406
1407 void
TC_DUMP_ENTRIES(struct xtc_handle * const handle)1408 TC_DUMP_ENTRIES(struct xtc_handle *const handle)
1409 {
1410 iptc_fn = TC_DUMP_ENTRIES;
1411
1412 printf("libiptc v%s. %u bytes.\n",
1413 XTABLES_VERSION, handle->entries->size);
1414 printf("Table `%s'\n", handle->info.name);
1415 printf("Hooks: pre/in/fwd/out/post = %x/%x/%x/%x/%x\n",
1416 handle->info.hook_entry[HOOK_PRE_ROUTING],
1417 handle->info.hook_entry[HOOK_LOCAL_IN],
1418 handle->info.hook_entry[HOOK_FORWARD],
1419 handle->info.hook_entry[HOOK_LOCAL_OUT],
1420 handle->info.hook_entry[HOOK_POST_ROUTING]);
1421 printf("Underflows: pre/in/fwd/out/post = %x/%x/%x/%x/%x\n",
1422 handle->info.underflow[HOOK_PRE_ROUTING],
1423 handle->info.underflow[HOOK_LOCAL_IN],
1424 handle->info.underflow[HOOK_FORWARD],
1425 handle->info.underflow[HOOK_LOCAL_OUT],
1426 handle->info.underflow[HOOK_POST_ROUTING]);
1427
1428 ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size,
1429 dump_entry, handle);
1430 }
1431
1432 /* Does this chain exist? */
TC_IS_CHAIN(const char * chain,struct xtc_handle * const handle)1433 int TC_IS_CHAIN(const char *chain, struct xtc_handle *const handle)
1434 {
1435 iptc_fn = TC_IS_CHAIN;
1436 return iptcc_find_label(chain, handle) != NULL;
1437 }
1438
iptcc_chain_iterator_advance(struct xtc_handle * handle)1439 static void iptcc_chain_iterator_advance(struct xtc_handle *handle)
1440 {
1441 struct chain_head *c = handle->chain_iterator_cur;
1442
1443 if (c->list.next == &handle->chains)
1444 handle->chain_iterator_cur = NULL;
1445 else
1446 handle->chain_iterator_cur =
1447 list_entry(c->list.next, struct chain_head, list);
1448 }
1449
1450 /* Iterator functions to run through the chains. */
1451 const char *
TC_FIRST_CHAIN(struct xtc_handle * handle)1452 TC_FIRST_CHAIN(struct xtc_handle *handle)
1453 {
1454 struct chain_head *c = list_entry(handle->chains.next,
1455 struct chain_head, list);
1456
1457 iptc_fn = TC_FIRST_CHAIN;
1458
1459
1460 if (list_empty(&handle->chains)) {
1461 DEBUGP(": no chains\n");
1462 return NULL;
1463 }
1464
1465 handle->chain_iterator_cur = c;
1466 iptcc_chain_iterator_advance(handle);
1467
1468 DEBUGP(": returning `%s'\n", c->name);
1469 return c->name;
1470 }
1471
1472 /* Iterator functions to run through the chains. Returns NULL at end. */
1473 const char *
TC_NEXT_CHAIN(struct xtc_handle * handle)1474 TC_NEXT_CHAIN(struct xtc_handle *handle)
1475 {
1476 struct chain_head *c = handle->chain_iterator_cur;
1477
1478 iptc_fn = TC_NEXT_CHAIN;
1479
1480 if (!c) {
1481 DEBUGP(": no more chains\n");
1482 return NULL;
1483 }
1484
1485 iptcc_chain_iterator_advance(handle);
1486
1487 DEBUGP(": returning `%s'\n", c->name);
1488 return c->name;
1489 }
1490
1491 /* Get first rule in the given chain: NULL for empty chain. */
1492 const STRUCT_ENTRY *
TC_FIRST_RULE(const char * chain,struct xtc_handle * handle)1493 TC_FIRST_RULE(const char *chain, struct xtc_handle *handle)
1494 {
1495 struct chain_head *c;
1496 struct rule_head *r;
1497
1498 iptc_fn = TC_FIRST_RULE;
1499
1500 DEBUGP("first rule(%s): ", chain);
1501
1502 c = iptcc_find_label(chain, handle);
1503 if (!c) {
1504 errno = ENOENT;
1505 return NULL;
1506 }
1507
1508 /* Empty chain: single return/policy rule */
1509 if (list_empty(&c->rules)) {
1510 DEBUGP_C("no rules, returning NULL\n");
1511 return NULL;
1512 }
1513
1514 r = list_entry(c->rules.next, struct rule_head, list);
1515 handle->rule_iterator_cur = r;
1516 DEBUGP_C("%p\n", r);
1517
1518 return r->entry;
1519 }
1520
1521 /* Returns NULL when rules run out. */
1522 const STRUCT_ENTRY *
TC_NEXT_RULE(const STRUCT_ENTRY * prev,struct xtc_handle * handle)1523 TC_NEXT_RULE(const STRUCT_ENTRY *prev, struct xtc_handle *handle)
1524 {
1525 struct rule_head *r;
1526
1527 iptc_fn = TC_NEXT_RULE;
1528 DEBUGP("rule_iterator_cur=%p...", handle->rule_iterator_cur);
1529
1530 if (handle->rule_iterator_cur == NULL) {
1531 DEBUGP_C("returning NULL\n");
1532 return NULL;
1533 }
1534
1535 r = list_entry(handle->rule_iterator_cur->list.next,
1536 struct rule_head, list);
1537
1538 iptc_fn = TC_NEXT_RULE;
1539
1540 DEBUGP_C("next=%p, head=%p...", &r->list,
1541 &handle->rule_iterator_cur->chain->rules);
1542
1543 if (&r->list == &handle->rule_iterator_cur->chain->rules) {
1544 handle->rule_iterator_cur = NULL;
1545 DEBUGP_C("finished, returning NULL\n");
1546 return NULL;
1547 }
1548
1549 handle->rule_iterator_cur = r;
1550
1551 /* NOTE: prev is without any influence ! */
1552 DEBUGP_C("returning rule %p\n", r);
1553 return r->entry;
1554 }
1555
1556 /* Returns a pointer to the target name of this position. */
standard_target_map(int verdict)1557 static const char *standard_target_map(int verdict)
1558 {
1559 switch (verdict) {
1560 case RETURN:
1561 return LABEL_RETURN;
1562 break;
1563 case -NF_ACCEPT-1:
1564 return LABEL_ACCEPT;
1565 break;
1566 case -NF_DROP-1:
1567 return LABEL_DROP;
1568 break;
1569 case -NF_QUEUE-1:
1570 return LABEL_QUEUE;
1571 break;
1572 default:
1573 fprintf(stderr, "ERROR: %d not a valid target)\n",
1574 verdict);
1575 abort();
1576 break;
1577 }
1578 /* not reached */
1579 return NULL;
1580 }
1581
1582 /* Returns a pointer to the target name of this position. */
TC_GET_TARGET(const STRUCT_ENTRY * ce,struct xtc_handle * handle)1583 const char *TC_GET_TARGET(const STRUCT_ENTRY *ce,
1584 struct xtc_handle *handle)
1585 {
1586 STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
1587 struct rule_head *r = container_of(e, struct rule_head, entry[0]);
1588 const unsigned char *data;
1589
1590 iptc_fn = TC_GET_TARGET;
1591
1592 switch(r->type) {
1593 int spos;
1594 case IPTCC_R_FALLTHROUGH:
1595 return "";
1596 break;
1597 case IPTCC_R_JUMP:
1598 DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name);
1599 return r->jump->name;
1600 break;
1601 case IPTCC_R_STANDARD:
1602 data = GET_TARGET(e)->data;
1603 spos = *(const int *)data;
1604 DEBUGP("r=%p, spos=%d'\n", r, spos);
1605 return standard_target_map(spos);
1606 break;
1607 case IPTCC_R_MODULE:
1608 return GET_TARGET(e)->u.user.name;
1609 break;
1610 }
1611 return NULL;
1612 }
1613 /* Is this a built-in chain? Actually returns hook + 1. */
1614 int
TC_BUILTIN(const char * chain,struct xtc_handle * const handle)1615 TC_BUILTIN(const char *chain, struct xtc_handle *const handle)
1616 {
1617 struct chain_head *c;
1618
1619 iptc_fn = TC_BUILTIN;
1620
1621 c = iptcc_find_label(chain, handle);
1622 if (!c) {
1623 errno = ENOENT;
1624 return 0;
1625 }
1626
1627 return iptcc_is_builtin(c);
1628 }
1629
1630 /* Get the policy of a given built-in chain */
1631 const char *
TC_GET_POLICY(const char * chain,STRUCT_COUNTERS * counters,struct xtc_handle * handle)1632 TC_GET_POLICY(const char *chain,
1633 STRUCT_COUNTERS *counters,
1634 struct xtc_handle *handle)
1635 {
1636 struct chain_head *c;
1637
1638 iptc_fn = TC_GET_POLICY;
1639
1640 DEBUGP("called for chain %s\n", chain);
1641
1642 c = iptcc_find_label(chain, handle);
1643 if (!c) {
1644 errno = ENOENT;
1645 return NULL;
1646 }
1647
1648 if (!iptcc_is_builtin(c))
1649 return NULL;
1650
1651 *counters = c->counters;
1652
1653 return standard_target_map(c->verdict);
1654 }
1655
1656 static int
iptcc_standard_map(struct rule_head * r,int verdict)1657 iptcc_standard_map(struct rule_head *r, int verdict)
1658 {
1659 STRUCT_ENTRY *e = r->entry;
1660 STRUCT_STANDARD_TARGET *t;
1661
1662 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1663
1664 if (t->target.u.target_size
1665 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
1666 errno = EINVAL;
1667 return 0;
1668 }
1669 /* memset for memcmp convenience on delete/replace */
1670 memset(t->target.u.user.name, 0, XT_EXTENSION_MAXNAMELEN);
1671 strcpy(t->target.u.user.name, STANDARD_TARGET);
1672 t->target.u.user.revision = 0;
1673 t->verdict = verdict;
1674
1675 r->type = IPTCC_R_STANDARD;
1676
1677 return 1;
1678 }
1679
1680 static int
iptcc_map_target(struct xtc_handle * const handle,struct rule_head * r,bool dry_run)1681 iptcc_map_target(struct xtc_handle *const handle,
1682 struct rule_head *r,
1683 bool dry_run)
1684 {
1685 STRUCT_ENTRY *e = r->entry;
1686 STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
1687
1688 /* Maybe it's empty (=> fall through) */
1689 if (strcmp(t->u.user.name, "") == 0) {
1690 r->type = IPTCC_R_FALLTHROUGH;
1691 return 1;
1692 }
1693 /* Maybe it's a standard target name... */
1694 else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
1695 return iptcc_standard_map(r, -NF_ACCEPT - 1);
1696 else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
1697 return iptcc_standard_map(r, -NF_DROP - 1);
1698 else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
1699 return iptcc_standard_map(r, -NF_QUEUE - 1);
1700 else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
1701 return iptcc_standard_map(r, RETURN);
1702 else if (TC_BUILTIN(t->u.user.name, handle)) {
1703 /* Can't jump to builtins. */
1704 errno = EINVAL;
1705 return 0;
1706 } else {
1707 /* Maybe it's an existing chain name. */
1708 struct chain_head *c;
1709 DEBUGP("trying to find chain `%s': ", t->u.user.name);
1710
1711 c = iptcc_find_label(t->u.user.name, handle);
1712 if (c) {
1713 DEBUGP_C("found!\n");
1714 r->type = IPTCC_R_JUMP;
1715 r->jump = c;
1716 c->references++;
1717 return 1;
1718 }
1719 DEBUGP_C("not found :(\n");
1720 }
1721
1722 /* Must be a module? If not, kernel will reject... */
1723 /* memset to all 0 for your memcmp convenience: don't clear version */
1724 memset(t->u.user.name + strlen(t->u.user.name),
1725 0,
1726 FUNCTION_MAXNAMELEN - 1 - strlen(t->u.user.name));
1727 r->type = IPTCC_R_MODULE;
1728 if (!dry_run)
1729 set_changed(handle);
1730 return 1;
1731 }
1732
1733 /* Insert the entry `fw' in chain `chain' into position `rulenum'. */
1734 int
TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,const STRUCT_ENTRY * e,unsigned int rulenum,struct xtc_handle * handle)1735 TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
1736 const STRUCT_ENTRY *e,
1737 unsigned int rulenum,
1738 struct xtc_handle *handle)
1739 {
1740 struct chain_head *c;
1741 struct rule_head *r;
1742 struct list_head *prev;
1743
1744 iptc_fn = TC_INSERT_ENTRY;
1745
1746 if (!(c = iptcc_find_label(chain, handle))) {
1747 errno = ENOENT;
1748 return 0;
1749 }
1750
1751 /* first rulenum index = 0
1752 first c->num_rules index = 1 */
1753 if (rulenum > c->num_rules) {
1754 errno = E2BIG;
1755 return 0;
1756 }
1757
1758 /* If we are inserting at the end just take advantage of the
1759 double linked list, insert will happen before the entry
1760 prev points to. */
1761 if (rulenum == c->num_rules) {
1762 prev = &c->rules;
1763 } else if (rulenum + 1 <= c->num_rules/2) {
1764 r = iptcc_get_rule_num(c, rulenum + 1);
1765 prev = &r->list;
1766 } else {
1767 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
1768 prev = &r->list;
1769 }
1770
1771 if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1772 errno = ENOMEM;
1773 return 0;
1774 }
1775
1776 memcpy(r->entry, e, e->next_offset);
1777 r->counter_map.maptype = COUNTER_MAP_SET;
1778
1779 if (!iptcc_map_target(handle, r, false)) {
1780 free(r);
1781 return 0;
1782 }
1783
1784 list_add_tail(&r->list, prev);
1785 c->num_rules++;
1786
1787 set_changed(handle);
1788
1789 return 1;
1790 }
1791
1792 /* Atomically replace rule `rulenum' in `chain' with `fw'. */
1793 int
TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,const STRUCT_ENTRY * e,unsigned int rulenum,struct xtc_handle * handle)1794 TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
1795 const STRUCT_ENTRY *e,
1796 unsigned int rulenum,
1797 struct xtc_handle *handle)
1798 {
1799 struct chain_head *c;
1800 struct rule_head *r, *old;
1801
1802 iptc_fn = TC_REPLACE_ENTRY;
1803
1804 if (!(c = iptcc_find_label(chain, handle))) {
1805 errno = ENOENT;
1806 return 0;
1807 }
1808
1809 if (rulenum >= c->num_rules) {
1810 errno = E2BIG;
1811 return 0;
1812 }
1813
1814 /* Take advantage of the double linked list if possible. */
1815 if (rulenum + 1 <= c->num_rules/2) {
1816 old = iptcc_get_rule_num(c, rulenum + 1);
1817 } else {
1818 old = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
1819 }
1820
1821 if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1822 errno = ENOMEM;
1823 return 0;
1824 }
1825
1826 memcpy(r->entry, e, e->next_offset);
1827 r->counter_map.maptype = COUNTER_MAP_SET;
1828
1829 if (!iptcc_map_target(handle, r, false)) {
1830 free(r);
1831 return 0;
1832 }
1833
1834 list_add(&r->list, &old->list);
1835 iptcc_delete_rule(old);
1836
1837 set_changed(handle);
1838
1839 return 1;
1840 }
1841
1842 /* Append entry `fw' to chain `chain'. Equivalent to insert with
1843 rulenum = length of chain. */
1844 int
TC_APPEND_ENTRY(const IPT_CHAINLABEL chain,const STRUCT_ENTRY * e,struct xtc_handle * handle)1845 TC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
1846 const STRUCT_ENTRY *e,
1847 struct xtc_handle *handle)
1848 {
1849 struct chain_head *c;
1850 struct rule_head *r;
1851
1852 iptc_fn = TC_APPEND_ENTRY;
1853 if (!(c = iptcc_find_label(chain, handle))) {
1854 DEBUGP("unable to find chain `%s'\n", chain);
1855 errno = ENOENT;
1856 return 0;
1857 }
1858
1859 if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1860 DEBUGP("unable to allocate rule for chain `%s'\n", chain);
1861 errno = ENOMEM;
1862 return 0;
1863 }
1864
1865 memcpy(r->entry, e, e->next_offset);
1866 r->counter_map.maptype = COUNTER_MAP_SET;
1867
1868 if (!iptcc_map_target(handle, r, false)) {
1869 DEBUGP("unable to map target of rule for chain `%s'\n", chain);
1870 free(r);
1871 return 0;
1872 }
1873
1874 list_add_tail(&r->list, &c->rules);
1875 c->num_rules++;
1876
1877 set_changed(handle);
1878
1879 return 1;
1880 }
1881
1882 static inline int
match_different(const STRUCT_ENTRY_MATCH * a,const unsigned char * a_elems,const unsigned char * b_elems,unsigned char ** maskptr)1883 match_different(const STRUCT_ENTRY_MATCH *a,
1884 const unsigned char *a_elems,
1885 const unsigned char *b_elems,
1886 unsigned char **maskptr)
1887 {
1888 const STRUCT_ENTRY_MATCH *b;
1889 unsigned int i;
1890
1891 /* Offset of b is the same as a. */
1892 b = (void *)b_elems + ((unsigned char *)a - a_elems);
1893
1894 if (a->u.match_size != b->u.match_size)
1895 return 1;
1896
1897 if (strcmp(a->u.user.name, b->u.user.name) != 0)
1898 return 1;
1899
1900 *maskptr += ALIGN(sizeof(*a));
1901
1902 for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
1903 if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1904 return 1;
1905 *maskptr += i;
1906 return 0;
1907 }
1908
1909 static inline int
target_same(struct rule_head * a,struct rule_head * b,const unsigned char * mask)1910 target_same(struct rule_head *a, struct rule_head *b,const unsigned char *mask)
1911 {
1912 unsigned int i;
1913 STRUCT_ENTRY_TARGET *ta, *tb;
1914
1915 if (a->type != b->type)
1916 return 0;
1917
1918 ta = GET_TARGET(a->entry);
1919 tb = GET_TARGET(b->entry);
1920
1921 switch (a->type) {
1922 case IPTCC_R_FALLTHROUGH:
1923 return 1;
1924 case IPTCC_R_JUMP:
1925 return a->jump == b->jump;
1926 case IPTCC_R_STANDARD:
1927 return ((STRUCT_STANDARD_TARGET *)ta)->verdict
1928 == ((STRUCT_STANDARD_TARGET *)tb)->verdict;
1929 case IPTCC_R_MODULE:
1930 if (ta->u.target_size != tb->u.target_size)
1931 return 0;
1932 if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
1933 return 0;
1934
1935 for (i = 0; i < ta->u.target_size - sizeof(*ta); i++)
1936 if (((ta->data[i] ^ tb->data[i]) & mask[i]) != 0)
1937 return 0;
1938 return 1;
1939 default:
1940 fprintf(stderr, "ERROR: bad type %i\n", a->type);
1941 abort();
1942 }
1943 }
1944
1945 static unsigned char *
1946 is_same(const STRUCT_ENTRY *a,
1947 const STRUCT_ENTRY *b,
1948 unsigned char *matchmask);
1949
1950
1951 /* find the first rule in `chain' which matches `fw' and remove it unless dry_run is set */
delete_entry(const IPT_CHAINLABEL chain,const STRUCT_ENTRY * origfw,unsigned char * matchmask,struct xtc_handle * handle,bool dry_run)1952 static int delete_entry(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw,
1953 unsigned char *matchmask, struct xtc_handle *handle,
1954 bool dry_run)
1955 {
1956 struct chain_head *c;
1957 struct rule_head *r, *i;
1958
1959 iptc_fn = TC_DELETE_ENTRY;
1960 if (!(c = iptcc_find_label(chain, handle))) {
1961 errno = ENOENT;
1962 return 0;
1963 }
1964
1965 /* Create a rule_head from origfw. */
1966 r = iptcc_alloc_rule(c, origfw->next_offset);
1967 if (!r) {
1968 errno = ENOMEM;
1969 return 0;
1970 }
1971
1972 memcpy(r->entry, origfw, origfw->next_offset);
1973 r->counter_map.maptype = COUNTER_MAP_NOMAP;
1974 if (!iptcc_map_target(handle, r, dry_run)) {
1975 DEBUGP("unable to map target of rule for chain `%s'\n", chain);
1976 free(r);
1977 return 0;
1978 } else {
1979 /* iptcc_map_target increment target chain references
1980 * since this is a fake rule only used for matching
1981 * the chain references count is decremented again.
1982 */
1983 if (r->type == IPTCC_R_JUMP
1984 && r->jump)
1985 r->jump->references--;
1986 }
1987
1988 list_for_each_entry(i, &c->rules, list) {
1989 unsigned char *mask;
1990
1991 mask = is_same(r->entry, i->entry, matchmask);
1992 if (!mask)
1993 continue;
1994
1995 if (!target_same(r, i, mask))
1996 continue;
1997
1998 /* if we are just doing a dry run, we simply skip the rest */
1999 if (dry_run){
2000 free(r);
2001 return 1;
2002 }
2003
2004 /* If we are about to delete the rule that is the
2005 * current iterator, move rule iterator back. next
2006 * pointer will then point to real next node */
2007 if (i == handle->rule_iterator_cur) {
2008 handle->rule_iterator_cur =
2009 list_entry(handle->rule_iterator_cur->list.prev,
2010 struct rule_head, list);
2011 }
2012
2013 c->num_rules--;
2014 iptcc_delete_rule(i);
2015
2016 set_changed(handle);
2017 free(r);
2018 return 1;
2019 }
2020
2021 free(r);
2022 errno = ENOENT;
2023 return 0;
2024 }
2025
2026 /* check whether a specified rule is present */
TC_CHECK_ENTRY(const IPT_CHAINLABEL chain,const STRUCT_ENTRY * origfw,unsigned char * matchmask,struct xtc_handle * handle)2027 int TC_CHECK_ENTRY(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw,
2028 unsigned char *matchmask, struct xtc_handle *handle)
2029 {
2030 /* do a dry-run delete to find out whether a matching rule exists */
2031 return delete_entry(chain, origfw, matchmask, handle, true);
2032 }
2033
2034 /* Delete the first rule in `chain' which matches `fw'. */
TC_DELETE_ENTRY(const IPT_CHAINLABEL chain,const STRUCT_ENTRY * origfw,unsigned char * matchmask,struct xtc_handle * handle)2035 int TC_DELETE_ENTRY(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw,
2036 unsigned char *matchmask, struct xtc_handle *handle)
2037 {
2038 return delete_entry(chain, origfw, matchmask, handle, false);
2039 }
2040
2041 /* Delete the rule in position `rulenum' in `chain'. */
2042 int
TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,unsigned int rulenum,struct xtc_handle * handle)2043 TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
2044 unsigned int rulenum,
2045 struct xtc_handle *handle)
2046 {
2047 struct chain_head *c;
2048 struct rule_head *r;
2049
2050 iptc_fn = TC_DELETE_NUM_ENTRY;
2051
2052 if (!(c = iptcc_find_label(chain, handle))) {
2053 errno = ENOENT;
2054 return 0;
2055 }
2056
2057 if (rulenum >= c->num_rules) {
2058 errno = E2BIG;
2059 return 0;
2060 }
2061
2062 /* Take advantage of the double linked list if possible. */
2063 if (rulenum + 1 <= c->num_rules/2) {
2064 r = iptcc_get_rule_num(c, rulenum + 1);
2065 } else {
2066 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
2067 }
2068
2069 /* If we are about to delete the rule that is the current
2070 * iterator, move rule iterator back. next pointer will then
2071 * point to real next node */
2072 if (r == handle->rule_iterator_cur) {
2073 handle->rule_iterator_cur =
2074 list_entry(handle->rule_iterator_cur->list.prev,
2075 struct rule_head, list);
2076 }
2077
2078 c->num_rules--;
2079 iptcc_delete_rule(r);
2080
2081 set_changed(handle);
2082
2083 return 1;
2084 }
2085
2086 /* Flushes the entries in the given chain (ie. empties chain). */
2087 int
TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain,struct xtc_handle * handle)2088 TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, struct xtc_handle *handle)
2089 {
2090 struct chain_head *c;
2091 struct rule_head *r, *tmp;
2092
2093 iptc_fn = TC_FLUSH_ENTRIES;
2094 if (!(c = iptcc_find_label(chain, handle))) {
2095 errno = ENOENT;
2096 return 0;
2097 }
2098
2099 list_for_each_entry_safe(r, tmp, &c->rules, list) {
2100 iptcc_delete_rule(r);
2101 }
2102
2103 c->num_rules = 0;
2104
2105 set_changed(handle);
2106
2107 return 1;
2108 }
2109
2110 /* Zeroes the counters in a chain. */
2111 int
TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain,struct xtc_handle * handle)2112 TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, struct xtc_handle *handle)
2113 {
2114 struct chain_head *c;
2115 struct rule_head *r;
2116
2117 iptc_fn = TC_ZERO_ENTRIES;
2118 if (!(c = iptcc_find_label(chain, handle))) {
2119 errno = ENOENT;
2120 return 0;
2121 }
2122
2123 if (c->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
2124 c->counter_map.maptype = COUNTER_MAP_ZEROED;
2125
2126 list_for_each_entry(r, &c->rules, list) {
2127 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
2128 r->counter_map.maptype = COUNTER_MAP_ZEROED;
2129 }
2130
2131 set_changed(handle);
2132
2133 return 1;
2134 }
2135
2136 STRUCT_COUNTERS *
TC_READ_COUNTER(const IPT_CHAINLABEL chain,unsigned int rulenum,struct xtc_handle * handle)2137 TC_READ_COUNTER(const IPT_CHAINLABEL chain,
2138 unsigned int rulenum,
2139 struct xtc_handle *handle)
2140 {
2141 struct chain_head *c;
2142 struct rule_head *r;
2143
2144 iptc_fn = TC_READ_COUNTER;
2145
2146 if (!(c = iptcc_find_label(chain, handle))) {
2147 errno = ENOENT;
2148 return NULL;
2149 }
2150
2151 if (!(r = iptcc_get_rule_num(c, rulenum))) {
2152 errno = E2BIG;
2153 return NULL;
2154 }
2155
2156 return &r->entry[0].counters;
2157 }
2158
2159 int
TC_ZERO_COUNTER(const IPT_CHAINLABEL chain,unsigned int rulenum,struct xtc_handle * handle)2160 TC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
2161 unsigned int rulenum,
2162 struct xtc_handle *handle)
2163 {
2164 struct chain_head *c;
2165 struct rule_head *r;
2166
2167 iptc_fn = TC_ZERO_COUNTER;
2168
2169 if (!(c = iptcc_find_label(chain, handle))) {
2170 errno = ENOENT;
2171 return 0;
2172 }
2173
2174 if (!(r = iptcc_get_rule_num(c, rulenum))) {
2175 errno = E2BIG;
2176 return 0;
2177 }
2178
2179 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
2180 r->counter_map.maptype = COUNTER_MAP_ZEROED;
2181
2182 set_changed(handle);
2183
2184 return 1;
2185 }
2186
2187 int
TC_SET_COUNTER(const IPT_CHAINLABEL chain,unsigned int rulenum,STRUCT_COUNTERS * counters,struct xtc_handle * handle)2188 TC_SET_COUNTER(const IPT_CHAINLABEL chain,
2189 unsigned int rulenum,
2190 STRUCT_COUNTERS *counters,
2191 struct xtc_handle *handle)
2192 {
2193 struct chain_head *c;
2194 struct rule_head *r;
2195 STRUCT_ENTRY *e;
2196
2197 iptc_fn = TC_SET_COUNTER;
2198
2199 if (!(c = iptcc_find_label(chain, handle))) {
2200 errno = ENOENT;
2201 return 0;
2202 }
2203
2204 if (!(r = iptcc_get_rule_num(c, rulenum))) {
2205 errno = E2BIG;
2206 return 0;
2207 }
2208
2209 e = r->entry;
2210 r->counter_map.maptype = COUNTER_MAP_SET;
2211
2212 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
2213
2214 set_changed(handle);
2215
2216 return 1;
2217 }
2218
2219 /* Creates a new chain. */
2220 /* To create a chain, create two rules: error node and unconditional
2221 * return. */
2222 int
TC_CREATE_CHAIN(const IPT_CHAINLABEL chain,struct xtc_handle * handle)2223 TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, struct xtc_handle *handle)
2224 {
2225 static struct chain_head *c;
2226 int capacity;
2227 int exceeded;
2228
2229 iptc_fn = TC_CREATE_CHAIN;
2230
2231 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
2232 QUEUE, RETURN. */
2233 if (iptcc_find_label(chain, handle)
2234 || strcmp(chain, LABEL_DROP) == 0
2235 || strcmp(chain, LABEL_ACCEPT) == 0
2236 || strcmp(chain, LABEL_QUEUE) == 0
2237 || strcmp(chain, LABEL_RETURN) == 0) {
2238 DEBUGP("Chain `%s' already exists\n", chain);
2239 errno = EEXIST;
2240 return 0;
2241 }
2242
2243 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
2244 DEBUGP("Chain name `%s' too long\n", chain);
2245 errno = EINVAL;
2246 return 0;
2247 }
2248
2249 c = iptcc_alloc_chain_head(chain, 0);
2250 if (!c) {
2251 DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
2252 errno = ENOMEM;
2253 return 0;
2254
2255 }
2256 handle->num_chains++; /* New user defined chain */
2257
2258 DEBUGP("Creating chain `%s'\n", chain);
2259 iptc_insert_chain(handle, c); /* Insert sorted */
2260
2261 /* Inserting chains don't change the correctness of the chain
2262 * index (except if its smaller than index[0], but that
2263 * handled by iptc_insert_chain). It only causes longer lists
2264 * in the buckets. Thus, only rebuild chain index when the
2265 * capacity is exceed with CHAIN_INDEX_INSERT_MAX chains.
2266 */
2267 capacity = handle->chain_index_sz * CHAIN_INDEX_BUCKET_LEN;
2268 exceeded = handle->num_chains - capacity;
2269 if (exceeded > CHAIN_INDEX_INSERT_MAX) {
2270 debug("Capacity(%d) exceeded(%d) rebuild (chains:%d)\n",
2271 capacity, exceeded, handle->num_chains);
2272 iptcc_chain_index_rebuild(handle);
2273 }
2274
2275 set_changed(handle);
2276
2277 return 1;
2278 }
2279
2280 /* Get the number of references to this chain. */
2281 int
TC_GET_REFERENCES(unsigned int * ref,const IPT_CHAINLABEL chain,struct xtc_handle * handle)2282 TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
2283 struct xtc_handle *handle)
2284 {
2285 struct chain_head *c;
2286
2287 iptc_fn = TC_GET_REFERENCES;
2288 if (!(c = iptcc_find_label(chain, handle))) {
2289 errno = ENOENT;
2290 return 0;
2291 }
2292
2293 *ref = c->references;
2294
2295 return 1;
2296 }
2297
2298 /* Deletes a chain. */
2299 int
TC_DELETE_CHAIN(const IPT_CHAINLABEL chain,struct xtc_handle * handle)2300 TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, struct xtc_handle *handle)
2301 {
2302 unsigned int references;
2303 struct chain_head *c;
2304
2305 iptc_fn = TC_DELETE_CHAIN;
2306
2307 if (!(c = iptcc_find_label(chain, handle))) {
2308 DEBUGP("cannot find chain `%s'\n", chain);
2309 errno = ENOENT;
2310 return 0;
2311 }
2312
2313 if (TC_BUILTIN(chain, handle)) {
2314 DEBUGP("cannot remove builtin chain `%s'\n", chain);
2315 errno = EINVAL;
2316 return 0;
2317 }
2318
2319 if (!TC_GET_REFERENCES(&references, chain, handle)) {
2320 DEBUGP("cannot get references on chain `%s'\n", chain);
2321 return 0;
2322 }
2323
2324 if (references > 0) {
2325 DEBUGP("chain `%s' still has references\n", chain);
2326 errno = EMLINK;
2327 return 0;
2328 }
2329
2330 if (c->num_rules) {
2331 DEBUGP("chain `%s' is not empty\n", chain);
2332 errno = ENOTEMPTY;
2333 return 0;
2334 }
2335
2336 /* If we are about to delete the chain that is the current
2337 * iterator, move chain iterator forward. */
2338 if (c == handle->chain_iterator_cur)
2339 iptcc_chain_iterator_advance(handle);
2340
2341 handle->num_chains--; /* One user defined chain deleted */
2342
2343 //list_del(&c->list); /* Done in iptcc_chain_index_delete_chain() */
2344 iptcc_chain_index_delete_chain(c, handle);
2345 free(c);
2346
2347 DEBUGP("chain `%s' deleted\n", chain);
2348
2349 set_changed(handle);
2350
2351 return 1;
2352 }
2353
2354 /* Renames a chain. */
TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,const IPT_CHAINLABEL newname,struct xtc_handle * handle)2355 int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
2356 const IPT_CHAINLABEL newname,
2357 struct xtc_handle *handle)
2358 {
2359 struct chain_head *c;
2360 iptc_fn = TC_RENAME_CHAIN;
2361
2362 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
2363 QUEUE, RETURN. */
2364 if (iptcc_find_label(newname, handle)
2365 || strcmp(newname, LABEL_DROP) == 0
2366 || strcmp(newname, LABEL_ACCEPT) == 0
2367 || strcmp(newname, LABEL_QUEUE) == 0
2368 || strcmp(newname, LABEL_RETURN) == 0) {
2369 errno = EEXIST;
2370 return 0;
2371 }
2372
2373 if (!(c = iptcc_find_label(oldname, handle))
2374 || TC_BUILTIN(oldname, handle)) {
2375 errno = ENOENT;
2376 return 0;
2377 }
2378
2379 if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
2380 errno = EINVAL;
2381 return 0;
2382 }
2383
2384 /* This only unlinks "c" from the list, thus no free(c) */
2385 iptcc_chain_index_delete_chain(c, handle);
2386
2387 /* Change the name of the chain */
2388 strncpy(c->name, newname, sizeof(IPT_CHAINLABEL) - 1);
2389
2390 /* Insert sorted into to list again */
2391 iptc_insert_chain(handle, c);
2392
2393 set_changed(handle);
2394
2395 return 1;
2396 }
2397
2398 /* Sets the policy on a built-in chain. */
2399 int
TC_SET_POLICY(const IPT_CHAINLABEL chain,const IPT_CHAINLABEL policy,STRUCT_COUNTERS * counters,struct xtc_handle * handle)2400 TC_SET_POLICY(const IPT_CHAINLABEL chain,
2401 const IPT_CHAINLABEL policy,
2402 STRUCT_COUNTERS *counters,
2403 struct xtc_handle *handle)
2404 {
2405 struct chain_head *c;
2406
2407 iptc_fn = TC_SET_POLICY;
2408
2409 if (!(c = iptcc_find_label(chain, handle))) {
2410 DEBUGP("cannot find chain `%s'\n", chain);
2411 errno = ENOENT;
2412 return 0;
2413 }
2414
2415 if (!iptcc_is_builtin(c)) {
2416 DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain);
2417 errno = ENOENT;
2418 return 0;
2419 }
2420
2421 if (strcmp(policy, LABEL_ACCEPT) == 0)
2422 c->verdict = -NF_ACCEPT - 1;
2423 else if (strcmp(policy, LABEL_DROP) == 0)
2424 c->verdict = -NF_DROP - 1;
2425 else {
2426 errno = EINVAL;
2427 return 0;
2428 }
2429
2430 if (counters) {
2431 /* set byte and packet counters */
2432 memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS));
2433 c->counter_map.maptype = COUNTER_MAP_SET;
2434 } else {
2435 c->counter_map.maptype = COUNTER_MAP_NOMAP;
2436 }
2437
2438 set_changed(handle);
2439
2440 return 1;
2441 }
2442
2443 /* Without this, on gcc 2.7.2.3, we get:
2444 libiptc.c: In function `TC_COMMIT':
2445 libiptc.c:833: fixed or forbidden register was spilled.
2446 This may be due to a compiler bug or to impossible asm
2447 statements or clauses.
2448 */
2449 static void
subtract_counters(STRUCT_COUNTERS * answer,const STRUCT_COUNTERS * a,const STRUCT_COUNTERS * b)2450 subtract_counters(STRUCT_COUNTERS *answer,
2451 const STRUCT_COUNTERS *a,
2452 const STRUCT_COUNTERS *b)
2453 {
2454 answer->pcnt = a->pcnt - b->pcnt;
2455 answer->bcnt = a->bcnt - b->bcnt;
2456 }
2457
2458
counters_nomap(STRUCT_COUNTERS_INFO * newcounters,unsigned int idx)2459 static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters, unsigned int idx)
2460 {
2461 newcounters->counters[idx] = ((STRUCT_COUNTERS) { 0, 0});
2462 DEBUGP_C("NOMAP => zero\n");
2463 }
2464
counters_normal_map(STRUCT_COUNTERS_INFO * newcounters,STRUCT_REPLACE * repl,unsigned int idx,unsigned int mappos)2465 static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
2466 STRUCT_REPLACE *repl, unsigned int idx,
2467 unsigned int mappos)
2468 {
2469 /* Original read: X.
2470 * Atomic read on replacement: X + Y.
2471 * Currently in kernel: Z.
2472 * Want in kernel: X + Y + Z.
2473 * => Add in X + Y
2474 * => Add in replacement read.
2475 */
2476 newcounters->counters[idx] = repl->counters[mappos];
2477 DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
2478 }
2479
counters_map_zeroed(STRUCT_COUNTERS_INFO * newcounters,STRUCT_REPLACE * repl,unsigned int idx,unsigned int mappos,STRUCT_COUNTERS * counters)2480 static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
2481 STRUCT_REPLACE *repl, unsigned int idx,
2482 unsigned int mappos, STRUCT_COUNTERS *counters)
2483 {
2484 /* Original read: X.
2485 * Atomic read on replacement: X + Y.
2486 * Currently in kernel: Z.
2487 * Want in kernel: Y + Z.
2488 * => Add in Y.
2489 * => Add in (replacement read - original read).
2490 */
2491 subtract_counters(&newcounters->counters[idx],
2492 &repl->counters[mappos],
2493 counters);
2494 DEBUGP_C("ZEROED => mappos %u\n", mappos);
2495 }
2496
counters_map_set(STRUCT_COUNTERS_INFO * newcounters,unsigned int idx,STRUCT_COUNTERS * counters)2497 static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
2498 unsigned int idx, STRUCT_COUNTERS *counters)
2499 {
2500 /* Want to set counter (iptables-restore) */
2501
2502 memcpy(&newcounters->counters[idx], counters,
2503 sizeof(STRUCT_COUNTERS));
2504
2505 DEBUGP_C("SET\n");
2506 }
2507
2508
2509 int
TC_COMMIT(struct xtc_handle * handle)2510 TC_COMMIT(struct xtc_handle *handle)
2511 {
2512 /* Replace, then map back the counters. */
2513 STRUCT_REPLACE *repl;
2514 STRUCT_COUNTERS_INFO *newcounters;
2515 struct chain_head *c;
2516 int ret;
2517 size_t counterlen;
2518 int new_number;
2519 unsigned int new_size;
2520
2521 iptc_fn = TC_COMMIT;
2522
2523 /* Don't commit if nothing changed. */
2524 if (!handle->changed)
2525 goto finished;
2526
2527 new_number = iptcc_compile_table_prep(handle, &new_size);
2528 if (new_number < 0) {
2529 errno = ENOMEM;
2530 goto out_zero;
2531 }
2532
2533 repl = malloc(sizeof(*repl) + new_size);
2534 if (!repl) {
2535 errno = ENOMEM;
2536 goto out_zero;
2537 }
2538 memset(repl, 0, sizeof(*repl) + new_size);
2539
2540 #if 0
2541 TC_DUMP_ENTRIES(*handle);
2542 #endif
2543
2544 counterlen = sizeof(STRUCT_COUNTERS_INFO)
2545 + sizeof(STRUCT_COUNTERS) * new_number;
2546
2547 /* These are the old counters we will get from kernel */
2548 repl->counters = malloc(sizeof(STRUCT_COUNTERS)
2549 * handle->info.num_entries);
2550 if (!repl->counters) {
2551 errno = ENOMEM;
2552 goto out_free_repl;
2553 }
2554 /* These are the counters we're going to put back, later. */
2555 newcounters = malloc(counterlen);
2556 if (!newcounters) {
2557 errno = ENOMEM;
2558 goto out_free_repl_counters;
2559 }
2560 memset(newcounters, 0, counterlen);
2561
2562 strcpy(repl->name, handle->info.name);
2563 repl->num_entries = new_number;
2564 repl->size = new_size;
2565
2566 repl->num_counters = handle->info.num_entries;
2567 repl->valid_hooks = handle->info.valid_hooks;
2568
2569 DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
2570 repl->num_entries, repl->size, repl->num_counters);
2571
2572 ret = iptcc_compile_table(handle, repl);
2573 if (ret < 0) {
2574 errno = ret;
2575 goto out_free_newcounters;
2576 }
2577
2578
2579 #ifdef IPTC_DEBUG2
2580 {
2581 int fd = open("/tmp/libiptc-so_set_replace.blob",
2582 O_CREAT|O_WRONLY, 0644);
2583 if (fd >= 0) {
2584 write(fd, repl, sizeof(*repl) + repl->size);
2585 close(fd);
2586 }
2587 }
2588 #endif
2589
2590 ret = setsockopt(handle->sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
2591 sizeof(*repl) + repl->size);
2592 if (ret < 0)
2593 goto out_free_newcounters;
2594
2595 /* Put counters back. */
2596 strcpy(newcounters->name, handle->info.name);
2597 newcounters->num_counters = new_number;
2598
2599 list_for_each_entry(c, &handle->chains, list) {
2600 struct rule_head *r;
2601
2602 /* Builtin chains have their own counters */
2603 if (iptcc_is_builtin(c)) {
2604 DEBUGP("counter for chain-index %u: ", c->foot_index);
2605 switch(c->counter_map.maptype) {
2606 case COUNTER_MAP_NOMAP:
2607 counters_nomap(newcounters, c->foot_index);
2608 break;
2609 case COUNTER_MAP_NORMAL_MAP:
2610 counters_normal_map(newcounters, repl,
2611 c->foot_index,
2612 c->counter_map.mappos);
2613 break;
2614 case COUNTER_MAP_ZEROED:
2615 counters_map_zeroed(newcounters, repl,
2616 c->foot_index,
2617 c->counter_map.mappos,
2618 &c->counters);
2619 break;
2620 case COUNTER_MAP_SET:
2621 counters_map_set(newcounters, c->foot_index,
2622 &c->counters);
2623 break;
2624 }
2625 }
2626
2627 list_for_each_entry(r, &c->rules, list) {
2628 DEBUGP("counter for index %u: ", r->index);
2629 switch (r->counter_map.maptype) {
2630 case COUNTER_MAP_NOMAP:
2631 counters_nomap(newcounters, r->index);
2632 break;
2633
2634 case COUNTER_MAP_NORMAL_MAP:
2635 counters_normal_map(newcounters, repl,
2636 r->index,
2637 r->counter_map.mappos);
2638 break;
2639
2640 case COUNTER_MAP_ZEROED:
2641 counters_map_zeroed(newcounters, repl,
2642 r->index,
2643 r->counter_map.mappos,
2644 &r->entry->counters);
2645 break;
2646
2647 case COUNTER_MAP_SET:
2648 counters_map_set(newcounters, r->index,
2649 &r->entry->counters);
2650 break;
2651 }
2652 }
2653 }
2654
2655 #ifdef IPTC_DEBUG2
2656 {
2657 int fd = open("/tmp/libiptc-so_set_add_counters.blob",
2658 O_CREAT|O_WRONLY, 0644);
2659 if (fd >= 0) {
2660 write(fd, newcounters, counterlen);
2661 close(fd);
2662 }
2663 }
2664 #endif
2665
2666 ret = setsockopt(handle->sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
2667 newcounters, counterlen);
2668 if (ret < 0)
2669 goto out_free_newcounters;
2670
2671 free(repl->counters);
2672 free(repl);
2673 free(newcounters);
2674
2675 finished:
2676 return 1;
2677
2678 out_free_newcounters:
2679 free(newcounters);
2680 out_free_repl_counters:
2681 free(repl->counters);
2682 out_free_repl:
2683 free(repl);
2684 out_zero:
2685 return 0;
2686 }
2687
2688 /* Translates errno numbers into more human-readable form than strerror. */
2689 const char *
TC_STRERROR(int err)2690 TC_STRERROR(int err)
2691 {
2692 unsigned int i;
2693 struct table_struct {
2694 void *fn;
2695 int err;
2696 const char *message;
2697 } table [] =
2698 { { TC_INIT, EPERM, "Permission denied (you must be root)" },
2699 { TC_INIT, EINVAL, "Module is wrong version" },
2700 { TC_INIT, ENOENT,
2701 "Table does not exist (do you need to insmod?)" },
2702 { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
2703 { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
2704 { TC_DELETE_CHAIN, EMLINK,
2705 "Can't delete chain with references left" },
2706 { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
2707 { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
2708 { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
2709 { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
2710 { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
2711 { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
2712 { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
2713 { TC_INSERT_ENTRY, EINVAL, "Target problem" },
2714 /* ENOENT for DELETE probably means no matching rule */
2715 { TC_DELETE_ENTRY, ENOENT,
2716 "Bad rule (does a matching rule exist in that chain?)" },
2717 { TC_SET_POLICY, ENOENT,
2718 "Bad built-in chain name" },
2719 { TC_SET_POLICY, EINVAL,
2720 "Bad policy name" },
2721
2722 { NULL, 0, "Incompatible with this kernel" },
2723 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
2724 { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" },
2725 { NULL, ENOMEM, "Memory allocation problem" },
2726 { NULL, ENOENT, "No chain/target/match by that name" },
2727 };
2728
2729 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
2730 if ((!table[i].fn || table[i].fn == iptc_fn)
2731 && table[i].err == err)
2732 return table[i].message;
2733 }
2734
2735 return strerror(err);
2736 }
2737
2738 const struct xtc_ops TC_OPS = {
2739 .commit = TC_COMMIT,
2740 .init = TC_INIT,
2741 .free = TC_FREE,
2742 .builtin = TC_BUILTIN,
2743 .is_chain = TC_IS_CHAIN,
2744 .flush_entries = TC_FLUSH_ENTRIES,
2745 .create_chain = TC_CREATE_CHAIN,
2746 .first_chain = TC_FIRST_CHAIN,
2747 .next_chain = TC_NEXT_CHAIN,
2748 .get_policy = TC_GET_POLICY,
2749 .set_policy = TC_SET_POLICY,
2750 .strerror = TC_STRERROR,
2751 };
2752