1 diff -Nur ipac-ng-1.31.orig/agents/iptables/iptables.c ipac-ng-1.31/agents/iptables/iptables.c
2 --- ipac-ng-1.31.orig/agents/iptables/iptables.c 2004-06-27 22:08:54.000000000 +0000
3 +++ ipac-ng-1.31/agents/iptables/iptables.c 2006-01-11 21:49:40.000000000 +0000
9 -#define IPT_LIB_DIR "/lib/iptables"
12 #define FMT_NUMERIC 0x0001
13 #define FMT_NOCOUNTS 0x0002
14 #define FMT_KILOMEGAGIGA 0x0004
16 static struct option *opts = original_opts;
17 static unsigned int global_option_offset = 0;
19 -extern char *authhost;
22 * interface structure to pass to append rule
24 typedef struct iface_struct s_iface;
27 +struct iptables_rule_match
29 + struct iptables_rule_match *next;
31 + struct iptables_match *match;
35 /* Include file for additions: new matches and targets. */
42 + /* Revision of match (0 by default). */
47 /* Size of match data. */
49 unsigned int option_offset;
50 struct ipt_entry_match *m;
55 struct iptables_target
60 + /* Revision of target (0 by default). */
65 /* Size of target data. */
78 +char *lib_dir = "/lib/iptables";
82 exit_error(enum exittype status, char *msg, ...)
85 * iptables-1.2.2 file:iptables.c
90 parse_interface(const char *arg, char *vianame, unsigned char *mask)
92 int vialen = strlen(arg);
94 " (%i)", arg, IFNAMSIZ-1);
98 + if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
99 memset(mask, 0, IFNAMSIZ);
100 else if (vianame[vialen - 1] == '+') {
101 memset(mask, 0xFF, vialen - 1);
102 memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
103 + /* Don't remove `+' here! -HW */
105 /* Include nul-terminator in match */
106 memset(mask, 0xFF, vialen + 1);
107 memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
109 for (i = 0; vianame[i]; i++) {
110 if (!isalnum(vianame[i])
112 - && vianame[i] != '+'
113 && vianame[i] != '.') {
114 - exit_error(PARAMETER_PROBLEM, "Warning: weird character in interface"
115 - " `%s' (No aliases, :, ! or *).\n", vianame);
116 + printf("Warning: wierd character in interface"
117 + " `%s' (No aliases, :, ! or *).\n",
124 @@ -429,20 +443,27 @@
128 -check_inverse(const char option[], int *invert)
129 +check_inverse(const char option[], int *invert, int *optind, int argc)
131 if (option && strcmp(option, "!") == 0) {
133 exit_error(PARAMETER_PROBLEM,
134 "Multiple `!' flags not allowed");
138 + *optind = *optind+1;
139 + if (argc && *optind > argc)
140 + exit_error(PARAMETER_PROBLEM,
141 + "no argument following `!'");
149 // ---------------------------------------------------------------------
150 +/* code copied from iptables 1.3.1 */
151 // ---------------------------------------------------------------------
155 return addr_to_dotted(addr);
160 mask_to_dotted(const struct in_addr *mask)
163 @@ -535,22 +556,19 @@
168 static struct ipt_entry *
169 generate_entry(const struct ipt_entry *fw,
170 - struct iptables_match *matches,
171 + struct iptables_rule_match *matches,
172 struct ipt_entry_target *target)
175 - struct iptables_match *m;
176 + struct iptables_rule_match *matchp;
179 size = sizeof(struct ipt_entry);
180 - for (m = matches; m; m = m->next) {
184 - size += m->m->u.match_size;
186 + for (matchp = matches; matchp; matchp = matchp->next)
187 + size += matchp->match->m->u.match_size;
189 e = xmalloc(size + target->u.target_size);
192 e->next_offset = size + target->u.target_size;
195 - for (m = matches; m; m = m->next) {
199 - memcpy(e->elems + size, m->m, m->m->u.match_size);
200 - size += m->m->u.match_size;
201 + for (matchp = matches; matchp; matchp = matchp->next) {
202 + memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size);
203 + size += matchp->match->m->u.match_size;
205 memcpy(e->elems + size, target, target->u.target_size);
207 @@ -575,15 +590,17 @@
211 +#define PROCFILE_BUFSIZ 1024
212 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
216 - ret = malloc(1024);
217 + ret = (char *) malloc(PROCFILE_BUFSIZ);
219 - switch (read(procfile, ret, 1024)) {
220 + memset(ret, 0, PROCFILE_BUFSIZ);
221 + switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
223 - case 1024: goto fail; /* Partial read. Wierd */
224 + case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */
226 if (ret[strlen(ret)-1]=='\n')
227 ret[strlen(ret)-1]=0;
228 @@ -618,22 +635,22 @@
231 if (!ptr && tryload != DONT_LOAD) {
232 - char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so")
233 + char path[strlen(lib_dir) + sizeof("/libipt_.so")
235 - sprintf(path, IPT_LIB_DIR "/libipt_%s.so", name);
236 + sprintf(path, "%s/libipt_%s.so", lib_dir, name);
237 if (dlopen(path, RTLD_NOW)) {
238 /* Found library. If it didn't register itself,
239 maybe they specified match as a target. */
240 ptr = find_target(name, DONT_LOAD);
242 - fprintf(stderr, "Couldn't load target `%s'\n",
243 + exit_error(PARAMETER_PROBLEM,
244 + "Couldn't load target `%s'\n",
248 } else if (tryload == LOAD_MUST_SUCCEED) {
249 - fprintf(stderr, "Couldn't load target `%s':%s\n",
250 + exit_error(PARAMETER_PROBLEM,
251 + "Couldn't load target `%s':%s\n",
263 -// If they don't explicitly set it, read out of kernel
264 + /* If they don't explicitly set it, read out of kernel */
266 buf = get_modprobe();
268 @@ -664,16 +682,18 @@
269 execv(argv[0], argv);
271 // not usually reached
283 + if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
291 if (me->size != IPT_ALIGN(me->size)) {
292 fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
293 - "fddfgdsse", me->name, me->size);
294 + "fddfgdsse", me->name, (unsigned int)me->size);
298 @@ -698,20 +718,17 @@
302 -unsigned char * make_delete_mask(struct ipt_entry *fw)
303 +static unsigned char *
304 +make_delete_mask(struct ipt_entry *fw, struct iptables_rule_match *matches)
306 /* Establish mask for comparison */
308 - struct iptables_match *m;
309 + struct iptables_rule_match *matchp;
310 unsigned char *mask, *mptr;
312 size = sizeof(struct ipt_entry);
313 - for (m = iptables_matches; m; m = m->next) {
317 - size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
319 + for (matchp = matches; matchp; matchp = matchp->next)
320 + size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size;
322 mask = xcalloc(1, size
323 + IPT_ALIGN(sizeof(struct ipt_entry_target))
324 @@ -720,14 +737,11 @@
325 memset(mask, 0xFF, sizeof(struct ipt_entry));
326 mptr = mask + sizeof(struct ipt_entry);
328 - for (m = iptables_matches; m; m = m->next) {
332 + for (matchp = matches; matchp; matchp = matchp->next) {
334 IPT_ALIGN(sizeof(struct ipt_entry_match))
335 - + m->userspacesize);
336 - mptr += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
337 + + matchp->match->userspacesize);
338 + mptr += IPT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size;
345 struct iptables_match *
346 -find_match(const char *name, enum ipt_tryload tryload)
347 +find_match(const char *name, enum ipt_tryload tryload, struct iptables_rule_match **matches)
349 struct iptables_match *ptr;
351 @@ -748,28 +762,37 @@
354 if (!ptr && tryload != DONT_LOAD) {
355 - char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so")
356 + char path[strlen(lib_dir) + sizeof("/libipt_.so")
358 - sprintf(path, IPT_LIB_DIR "/libipt_%s.so", name);
359 + sprintf(path, "%s/libipt_%s.so", lib_dir, name);
360 if (dlopen(path, RTLD_NOW)) {
361 /* Found library. If it didn't register itself,
362 maybe they specified target as match. */
363 - ptr = find_match(name, DONT_LOAD);
364 + ptr = find_match(name, DONT_LOAD, NULL);
367 - fprintf(stderr, "Couldn't load match `%s'\n",
368 + exit_error(PARAMETER_PROBLEM,
369 + "Couldn't load match `%s'\n",
373 } else if (tryload == LOAD_MUST_SUCCEED) {
374 - fprintf(stderr, "Couldn't load match `%s':%s\n",
375 + exit_error(PARAMETER_PROBLEM,
376 + "Couldn't load match `%s':%s\n",
384 + if (ptr && matches) {
385 + struct iptables_rule_match **i;
386 + struct iptables_rule_match *newentry;
388 + newentry = xmalloc(sizeof(struct iptables_rule_match));
390 + for (i = matches; *i; i = &(*i)->next);
391 + newentry->match = ptr;
392 + newentry->next = NULL;
400 struct iptables_match **i;
402 - if (find_match(me->name, DONT_LOAD)) {
403 + if (find_match(me->name, DONT_LOAD, NULL)) {
404 fprintf(stderr, "%s: match `%s' already registered.\n",
405 "fetchipac??", me->name);
409 if (me->size != IPT_ALIGN(me->size)) {
410 fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
411 - "fetchipac??", me->name, me->size);
412 + "fetchipac??", me->name, (unsigned int)me->size);
416 @@ -801,16 +824,21 @@
420 +/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
421 static struct iptables_match *
422 -find_proto(const char *pname, enum ipt_tryload tryload, int nolookup)
423 +find_proto(const char *pname, enum ipt_tryload tryload, int nolookup, struct iptables_rule_match **matches)
426 + unsigned int proto;
428 - proto = string_to_number(pname, 0, 255);
430 - return find_match(proto_to_name(proto, nolookup), tryload);
431 + if ((proto = string_to_number(pname, 0, 255)) != -1) {
432 + char *protoname = proto_to_name(proto, nolookup);
434 - return find_match(pname, tryload);
436 + return find_match(protoname, tryload, matches);
438 + return find_match(pname, tryload, matches);
444 @@ -823,15 +851,19 @@
445 number = (number + 500) / 1000;
447 number = (number + 500) / 1000;
448 - printf(FMT("%4lluG ","%lluG "),number);
449 + if (number > 9999) {
450 + number = (number + 500) / 1000;
451 + printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
453 - else printf(FMT("%4lluM ","%lluM "), number);
454 + else printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
456 + else printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
458 - printf(FMT("%4lluK ","%lluK "), number);
459 + printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
461 - printf(FMT("%5llu ","%llu "), number);
462 + printf(FMT("%5llu ","%llu "), (unsigned long long)number);
464 - printf(FMT("%8llu ","%llu "), number);
465 + printf(FMT("%8llu ","%llu "), (unsigned long long)number);
470 const struct ipt_ip *ip,
473 - struct iptables_match *match = find_match(m->u.user.name, TRY_LOAD);
474 + struct iptables_match *match = find_match(m->u.user.name, TRY_LOAD, NULL);
482 - /* User creates a chain called "REJECT": this overrides the
483 - `REJECT' target module. Keep feeding them rope until the
484 - revolution... Bwahahahahah */
485 if (!iptc_is_chain(targname, handle))
486 target = find_target(targname, TRY_LOAD);
490 if (fw->ip.iniface[0] != '\0') {
491 strcat(iface, fw->ip.iniface);
492 - /* If it doesn't compare the nul-term, it's a
494 - if (fw->ip.iniface_mask[strlen(fw->ip.iniface)] == 0)
495 - strcat(iface, "+");
497 else if (format & FMT_NUMERIC) strcat(iface, "*");
498 else strcat(iface, "any");
501 if (fw->ip.outiface[0] != '\0') {
502 strcat(iface, fw->ip.outiface);
503 - /* If it doesn't compare the nul-term, it's a
505 - if (fw->ip.outiface_mask[strlen(fw->ip.outiface)] == 0)
506 - strcat(iface, "+");
508 else if (format & FMT_NUMERIC) strcat(iface, "*");
509 else strcat(iface, "any");
511 target->print(&fw->ip, t, format & FMT_NUMERIC);
512 } else if (t->u.target_size != sizeof(*t))
513 printf("[%u bytes of unknown target data] ",
514 - t->u.target_size - sizeof(*t));
515 + (unsigned int)(t->u.target_size - sizeof(*t)));
517 if (!(format & FMT_NONEWLINE))
519 @@ -996,6 +1017,15 @@
523 +static void set_revision(char *name, u_int8_t revision)
525 + /* Old kernel sources don't have ".revision" field,
526 + but we stole a byte from name. */
527 + name[IPT_FUNCTION_MAXNAMELEN - 2] = '\0';
528 + name[IPT_FUNCTION_MAXNAMELEN - 1] = revision;
532 // ---------------------------------------------------------------------
535 @@ -1129,8 +1159,7 @@
540 - counters = iptc_read_counter(chain->name, chain->pkts, &handle);
541 + counters = iptc_read_counter(chain->name, chain->pkts, &handle); // ???? why chain->pkts
543 iptc_zero_counter(chain->name, chain->pkts, &handle);
545 @@ -1192,7 +1221,7 @@
549 -prepare_entry (raw_rule_type *d, struct ipt_entry **e)
550 +prepare_entry (raw_rule_type *d, struct ipt_entry **e, struct iptables_rule_match **matches)
553 unsigned int naddrs = 0;
554 @@ -1200,10 +1229,14 @@
555 struct iptables_match *m;
556 struct iptables_target *target = NULL;
557 struct iptables_target *t;
559 + struct iptables_rule_match *matchp;
565 + int proto_used = 0;
567 bzero(&fw, sizeof(fw));
569 @@ -1233,7 +1266,6 @@
571 for (m = iptables_matches; m; m = m->next) {
576 for (t = iptables_targets; t; t = t->next) {
577 @@ -1279,6 +1311,8 @@
578 target->t = xcalloc(1, size);
579 target->t->u.target_size = size;
580 strcpy(target->t->u.user.name, d->target);
581 + set_revision(target->t->u.user.name, target->revision);
582 + if (target->init != NULL)
583 target->init(target->t, &fw.nfcache);
585 if(check_inverse_type(d->protocol))
586 @@ -1290,7 +1324,7 @@
589 if (d->protocol[0] != '\0' && d->protocol[0] != 'i') {
590 - m = find_proto(d->protocol, LOAD_MUST_SUCCEED, 0);
591 + m = find_proto(d->protocol, LOAD_MUST_SUCCEED, 0, matches);
592 size = IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
593 m->m = xcalloc(size, 1);
594 m->m->u.match_size = size;
595 @@ -1338,7 +1372,7 @@
596 while ((c = getopt_long(argc, d->extension,"-m:", opts, NULL))!= -1) {
599 - m = find_match(optarg, LOAD_MUST_SUCCEED);
600 + m = find_match(optarg, LOAD_MUST_SUCCEED, matches);
601 size = IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
602 m->m = xcalloc(1, size);
603 m->m->u.match_size = size;
604 @@ -1361,32 +1395,80 @@
608 - for (m = iptables_matches; m; m = m->next) {
611 - if (m->parse(c - m->option_offset,
613 + /* FIXME: This scheme doesn't allow two of the same
616 + || !(target->parse(c - target->option_offset,
617 + d->extension, invert,
619 + &fw, &target->t))) {
620 + for (matchp = *matches; matchp; matchp = matchp->next) {
621 + if (matchp->match->parse(c - matchp->match->option_offset,
622 d->extension, invert,
624 - &fw, &fw.nfcache, &m->m))
625 + &matchp->match->mflags,
628 + &matchp->match->m))
635 + && (!find_proto(d->protocol, DONT_LOAD,
637 + || (find_proto(d->protocol, DONT_LOAD,
639 + && (proto_used == 0))
641 + && (m = find_proto(d->protocol, TRY_LOAD,
643 + /* Try loading protocol */
648 + size = IPT_ALIGN(sizeof(struct ipt_entry_match))
651 + m->m = xcalloc(1, size);
652 + m->m->u.match_size = size;
653 + strcpy(m->m->u.user.name, m->name);
654 + set_revision(m->m->u.user.name,
656 + if (m->init != NULL)
657 + m->init(m->m, &fw.nfcache);
659 + opts = merge_options(opts,
660 + m->extra_opts, &m->option_offset);
666 + m = matchp ? matchp->match : NULL;
668 + exit_error(PARAMETER_PROBLEM,
669 + "Unknown arg `%s'",
674 - for (m = iptables_matches; m; m = m->next) {
677 - m->final_check(m->mflags);
680 + for (matchp = *matches; matchp; matchp = matchp->next)
681 + matchp->match->final_check(matchp->match->mflags);
684 target->final_check(target->tflags);
685 - *e = generate_entry(&fw, iptables_matches, target->t);
687 + *e = generate_entry(&fw, *matches, target->t);
691 if (!handle) if (!(handle = iptc_init("filter")))
692 exit_error(PARAMETER_PROBLEM,
693 "iptables: %s\n", iptc_strerror(errno));
698 @@ -1399,9 +1481,11 @@
699 insert_rule(raw_rule_type *d, int rule_num)
701 struct ipt_entry *e = NULL;
702 + struct iptables_rule_match *matches = NULL;
706 - if (prepare_entry(d, &e)!=0)
707 + if (prepare_entry(d, &e, &matches)!=0)
710 printf("Inserting rule\n");
711 @@ -1412,28 +1496,6 @@
716 - * Try to atomically replace rule in kernel return 0 in case all right, 1 otherwice
719 -//replace_rule (char *chain, char *saddr, char *sport, char *daddr, char *dport,
720 -// char *proto, char *targ, int rule_num, char *iface)
721 -replace_rule (raw_rule_type *d, int rule_num)
723 - struct ipt_entry *e = NULL;
726 - if (prepare_entry(d, &e)!=0)
730 - printf("Replacing rule %d in '%s'\n", rule_num, d->dest);
731 - print_firewall_line(e, handle);
733 - ret &= iptc_replace_entry(d->dest, e, rule_num, &handle);
739 * Try to append rule into kernel return 0 in case all right, 1 otherwice
740 @@ -1449,8 +1511,9 @@
741 append_rule (raw_rule_type *d)
743 struct ipt_entry *e = NULL;
744 + struct iptables_rule_match *matches = NULL;
746 - if (prepare_entry(d, &e)!=0)
747 + if (prepare_entry(d, &e, &matches)!=0)
751 @@ -1472,9 +1535,11 @@
753 struct ipt_entry *e = NULL;
754 unsigned char *mask = NULL;
755 + struct iptables_rule_match *matches = NULL;
759 - if (prepare_entry(d, &e)!=0)
760 + if (prepare_entry(d, &e, &matches)!=0)
764 @@ -1482,26 +1547,12 @@
765 print_firewall_line(e, handle);
768 - mask = make_delete_mask(e);
769 + mask = make_delete_mask(e, matches);
770 ret &= iptc_delete_entry(d->dest, e, mask, &handle);
776 -delete_num_rule (char *chain, int num)
778 - struct ipt_entry *e = NULL;
779 - unsigned char *mask = NULL;
782 - mask = make_delete_mask(e);
783 - ret &= iptc_delete_num_entry(chain, num, &handle);
790 /** Setup chains if they doesn't exist
792 @@ -1588,11 +1639,9 @@
794 handle = iptc_init("filter");
797 -// try to insmod the module if iptc_init failed
798 - iptables_insmod("ip_tables", modprobe);
799 + /* try to insmod the module if iptc_init failed */
800 + if (!handle && iptables_insmod("ip_tables", modprobe) != -1)
801 handle = iptc_init("filter");
805 fprintf(stderr, "ipac-ng: can't initialize iptables table `filter'\n"
806 @@ -1617,7 +1666,6 @@
809 raw_rule_type *d, *d1;
810 - char targ[MAX_RULE_NAME_LENGTH+2];
811 char chain[MAX_RULE_NAME_LENGTH+2];
814 diff -Nur ipac-ng-1.31.orig/agents/iptables/libip4tc.c ipac-ng-1.31/agents/iptables/libip4tc.c
815 --- ipac-ng-1.31.orig/agents/iptables/libip4tc.c 2003-07-06 10:33:23.000000000 +0000
816 +++ ipac-ng-1.31/agents/iptables/libip4tc.c 2006-01-11 21:51:46.000000000 +0000
823 #ifdef DEBUG_CONNTRACK
826 #define TC_SET_POLICY iptc_set_policy
827 #define TC_GET_RAW_SOCKET iptc_get_raw_socket
828 #define TC_INIT iptc_init
829 +#define TC_FREE iptc_free
830 #define TC_COMMIT iptc_commit
831 #define TC_STRERROR iptc_strerror
833 @@ -121,121 +123,49 @@
835 #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
838 -dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle)
841 - STRUCT_ENTRY_TARGET *t;
843 - printf("Entry %u (%lu):\n", entry2index(handle, e),
844 - entry2offset(handle, e));
845 - printf("SRC IP: %u.%u.%u.%u/%u.%u.%u.%u\n",
846 - IP_PARTS(e->ip.src.s_addr),IP_PARTS(e->ip.smsk.s_addr));
847 - printf("DST IP: %u.%u.%u.%u/%u.%u.%u.%u\n",
848 - IP_PARTS(e->ip.dst.s_addr),IP_PARTS(e->ip.dmsk.s_addr));
849 - printf("Interface: `%s'/", e->ip.iniface);
850 - for (i = 0; i < IFNAMSIZ; i++)
851 - printf("%c", e->ip.iniface_mask[i] ? 'X' : '.');
852 - printf("to `%s'/", e->ip.outiface);
853 - for (i = 0; i < IFNAMSIZ; i++)
854 - printf("%c", e->ip.outiface_mask[i] ? 'X' : '.');
855 - printf("\nProtocol: %u\n", e->ip.proto);
856 - printf("Flags: %02X\n", e->ip.flags);
857 - printf("Invflags: %02X\n", e->ip.invflags);
858 - printf("Counters: %llu packets, %llu bytes\n",
859 - e->counters.pcnt, e->counters.bcnt);
860 - printf("Cache: %08X ", e->nfcache);
861 - if (e->nfcache & NFC_ALTERED) printf("ALTERED ");
862 - if (e->nfcache & NFC_UNKNOWN) printf("UNKNOWN ");
863 - if (e->nfcache & NFC_IP_SRC) printf("IP_SRC ");
864 - if (e->nfcache & NFC_IP_DST) printf("IP_DST ");
865 - if (e->nfcache & NFC_IP_IF_IN) printf("IP_IF_IN ");
866 - if (e->nfcache & NFC_IP_IF_OUT) printf("IP_IF_OUT ");
867 - if (e->nfcache & NFC_IP_TOS) printf("IP_TOS ");
868 - if (e->nfcache & NFC_IP_PROTO) printf("IP_PROTO ");
869 - if (e->nfcache & NFC_IP_OPTIONS) printf("IP_OPTIONS ");
870 - if (e->nfcache & NFC_IP_TCPFLAGS) printf("IP_TCPFLAGS ");
871 - if (e->nfcache & NFC_IP_SRC_PT) printf("IP_SRC_PT ");
872 - if (e->nfcache & NFC_IP_DST_PT) printf("IP_DST_PT ");
873 - if (e->nfcache & NFC_IP_PROTO_UNKNOWN) printf("IP_PROTO_UNKNOWN ");
876 - IPT_MATCH_ITERATE(e, print_match);
879 - printf("Target name: `%s' [%u]\n", t->u.user.name, t->u.target_size);
880 - if (strcmp(t->u.user.name, STANDARD_TARGET) == 0) {
881 - int pos = *(int *)t->data;
883 - printf("verdict=%s\n",
884 - pos == -NF_ACCEPT-1 ? "NF_ACCEPT"
885 - : pos == -NF_DROP-1 ? "NF_DROP"
886 - : pos == -NF_QUEUE-1 ? "NF_QUEUE"
887 - : pos == RETURN ? "RETURN"
890 - printf("verdict=%u\n", pos);
891 - } else if (strcmp(t->u.user.name, IPT_ERROR_TARGET) == 0)
892 - printf("error=`%s'\n", t->data);
899 +static unsigned char *
900 is_same(const STRUCT_ENTRY *a, const STRUCT_ENTRY *b, unsigned char *matchmask)
903 - STRUCT_ENTRY_TARGET *ta, *tb;
906 /* Always compare head structures: ignore mask here. */
907 if (a->ip.src.s_addr != b->ip.src.s_addr
908 || a->ip.dst.s_addr != b->ip.dst.s_addr
909 || a->ip.smsk.s_addr != b->ip.smsk.s_addr
910 - || a->ip.smsk.s_addr != b->ip.smsk.s_addr
911 + || a->ip.dmsk.s_addr != b->ip.dmsk.s_addr
912 || a->ip.proto != b->ip.proto
913 || a->ip.flags != b->ip.flags
914 || a->ip.invflags != b->ip.invflags)
918 for (i = 0; i < IFNAMSIZ; i++) {
919 if (a->ip.iniface_mask[i] != b->ip.iniface_mask[i])
922 if ((a->ip.iniface[i] & a->ip.iniface_mask[i])
923 != (b->ip.iniface[i] & b->ip.iniface_mask[i]))
926 if (a->ip.outiface_mask[i] != b->ip.outiface_mask[i])
929 if ((a->ip.outiface[i] & a->ip.outiface_mask[i])
930 != (b->ip.outiface[i] & b->ip.outiface_mask[i]))
935 if (a->nfcache != b->nfcache
936 || a->target_offset != b->target_offset
937 || a->next_offset != b->next_offset)
941 mptr = matchmask + sizeof(STRUCT_ENTRY);
942 if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems, &mptr))
946 - ta = GET_TARGET((STRUCT_ENTRY *)a);
947 - tb = GET_TARGET((STRUCT_ENTRY *)b);
948 - if (ta->u.target_size != tb->u.target_size)
950 - if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
953 - mptr += sizeof(*ta);
954 - if (target_different(ta->data, tb->data,
955 - ta->u.target_size - sizeof(*ta), mptr))
963 /***************************** DEBUGGING ********************************/
965 unconditional(const struct ipt_ip *ip)
966 @@ -290,20 +220,20 @@
967 assert(t->verdict == -NF_DROP-1
968 || t->verdict == -NF_ACCEPT-1
969 || t->verdict == RETURN
970 - || t->verdict < (int)h->entries.size);
971 + || t->verdict < (int)h->entries->size);
973 if (t->verdict >= 0) {
974 STRUCT_ENTRY *te = get_entry(h, t->verdict);
977 - idx = entry2index(h, te);
978 + idx = iptcb_entry2index(h, te);
979 assert(strcmp(GET_TARGET(te)->u.user.name,
984 /* Prior node must be error node, or this node. */
985 - assert(t->verdict == entry2offset(h, e)+e->next_offset
986 + assert(t->verdict == iptcb_entry2offset(h, e)+e->next_offset
987 || strcmp(GET_TARGET(index2entry(h, idx-1))
988 ->u.user.name, IPT_ERROR_TARGET)
996 /* Do every conceivable sanity check on the handle */
998 do_check(TC_HANDLE_T h, unsigned int line)
999 @@ -364,35 +294,90 @@
1001 user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1002 } else if (strcmp(h->info.name, "nat") == 0) {
1003 - assert(h->info.valid_hooks
1004 + assert((h->info.valid_hooks
1005 == (1 << NF_IP_PRE_ROUTING
1006 | 1 << NF_IP_POST_ROUTING
1007 - | 1 << NF_IP_LOCAL_OUT));
1008 + | 1 << NF_IP_LOCAL_OUT)) ||
1009 + (h->info.valid_hooks
1010 + == (1 << NF_IP_PRE_ROUTING
1011 + | 1 << NF_IP_LOCAL_IN
1012 + | 1 << NF_IP_POST_ROUTING
1013 + | 1 << NF_IP_LOCAL_OUT)));
1015 assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1017 n = get_chain_end(h, 0);
1019 n += get_entry(h, n)->next_offset;
1020 assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n);
1022 n = get_chain_end(h, n);
1024 n += get_entry(h, n)->next_offset;
1025 assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1027 user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1029 + if (h->info.valid_hooks & (1 << NF_IP_LOCAL_IN)) {
1030 + n = get_chain_end(h, n);
1031 + n += get_entry(h, n)->next_offset;
1032 + assert(h->info.hook_entry[NF_IP_LOCAL_IN] == n);
1033 + user_offset = h->info.hook_entry[NF_IP_LOCAL_IN];
1036 } else if (strcmp(h->info.name, "mangle") == 0) {
1037 + /* This code is getting ugly because linux < 2.4.18-pre6 had
1038 + * two mangle hooks, linux >= 2.4.18-pre6 has five mangle hooks
1040 + assert((h->info.valid_hooks
1041 + == (1 << NF_IP_PRE_ROUTING
1042 + | 1 << NF_IP_LOCAL_OUT)) ||
1043 + (h->info.valid_hooks
1044 + == (1 << NF_IP_PRE_ROUTING
1045 + | 1 << NF_IP_LOCAL_IN
1046 + | 1 << NF_IP_FORWARD
1047 + | 1 << NF_IP_LOCAL_OUT
1048 + | 1 << NF_IP_POST_ROUTING)));
1050 + /* Hooks should be first five */
1051 + assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1053 + n = get_chain_end(h, 0);
1055 + if (h->info.valid_hooks & (1 << NF_IP_LOCAL_IN)) {
1056 + n += get_entry(h, n)->next_offset;
1057 + assert(h->info.hook_entry[NF_IP_LOCAL_IN] == n);
1058 + n = get_chain_end(h, n);
1061 + if (h->info.valid_hooks & (1 << NF_IP_FORWARD)) {
1062 + n += get_entry(h, n)->next_offset;
1063 + assert(h->info.hook_entry[NF_IP_FORWARD] == n);
1064 + n = get_chain_end(h, n);
1067 + n += get_entry(h, n)->next_offset;
1068 + assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1069 + user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1071 + if (h->info.valid_hooks & (1 << NF_IP_POST_ROUTING)) {
1072 + n = get_chain_end(h, n);
1073 + n += get_entry(h, n)->next_offset;
1074 + assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n);
1075 + user_offset = h->info.hook_entry[NF_IP_POST_ROUTING];
1077 + } else if (strcmp(h->info.name, "raw") == 0) {
1078 assert(h->info.valid_hooks
1079 == (1 << NF_IP_PRE_ROUTING
1080 | 1 << NF_IP_LOCAL_OUT));
1082 - /* Hooks should be first two */
1083 + /* Hooks should be first three */
1084 assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1086 - n = get_chain_end(h, 0);
1087 + n = get_chain_end(h, n);
1088 n += get_entry(h, n)->next_offset;
1089 assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1091 user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1093 #ifdef NF_IP_DROPPING
1094 } else if (strcmp(h->info.name, "drop") == 0) {
1095 assert(h->info.valid_hooks == (1 << NF_IP_DROPPING));
1097 assert(unconditional(&e->ip));
1098 assert(e->target_offset == sizeof(*e));
1099 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1100 - assert(t->target.u.target_size == IPT_ALIGN(sizeof(*t)));
1101 - assert(e->next_offset == sizeof(*e) + IPT_ALIGN(sizeof(*t)));
1102 + assert(t->target.u.target_size == ALIGN(sizeof(*t)));
1103 + assert(e->next_offset == sizeof(*e) + ALIGN(sizeof(*t)));
1105 assert(strcmp(t->target.u.user.name, STANDARD_TARGET)==0);
1106 assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1);
1108 /* Final entry must be error node */
1109 assert(strcmp(GET_TARGET(index2entry(h, h->new_number-1))
1111 - IPT_ERROR_TARGET) == 0);
1112 + ERROR_TARGET) == 0);
1115 +#endif /*IPTC_DEBUG*/
1118 diff -Nur ipac-ng-1.31.orig/agents/iptables/libiptc.c ipac-ng-1.31/agents/iptables/libiptc.c
1119 --- ipac-ng-1.31.orig/agents/iptables/libiptc.c 2003-07-06 11:34:52.000000000 +0000
1120 +++ ipac-ng-1.31/agents/iptables/libiptc.c 2006-01-10 21:01:39.000000000 +0000
1124 /* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
1125 - COPYING for details). */
1126 + * COPYING for details).
1127 + * (C) 2000-2004 by the Netfilter Core Team <coreteam@netfilter.org>
1129 + * 2003-Jun-20: Harald Welte <laforge@netfilter.org>:
1130 + * - Reimplementation of chain cache to use offsets instead of entries
1131 + * 2003-Jun-23: Harald Welte <laforge@netfilter.org>:
1132 + * - performance optimization, sponsored by Astaro AG (http://www.astaro.com/)
1133 + * don't rebuild the chain cache after every operation, instead fix it
1134 + * up after a ruleset change.
1135 + * 2004-Aug-18: Harald Welte <laforge@netfilter.org>:
1136 + * - futher performance work: total reimplementation of libiptc.
1137 + * - libiptc now has a real internal (linked-list) represntation of the
1138 + * ruleset and a parser/compiler from/to this internal representation
1139 + * - again sponsored by Astaro AG (http://www.astaro.com/)
1141 +#include <sys/types.h>
1142 +#include <sys/socket.h>
1144 -#ifndef IPT_LIB_DIR
1145 -#define IPT_LIB_DIR "/lib/iptables"
1146 +#include "linux_list.h"
1148 +//#define IPTC_DEBUG2 1
1152 +#define DEBUGP(x, args...) fprintf(stderr, "%s: " x, __FUNCTION__, ## args)
1153 +#define DEBUGP_C(x, args...) fprintf(stderr, x, ## args)
1155 +#define DEBUGP(x, args...)
1156 +#define DEBUGP_C(x, args...)
1159 -#ifndef __OPTIMIZE__
1160 -STRUCT_ENTRY_TARGET *
1161 -GET_TARGET(STRUCT_ENTRY *e)
1163 - return (void *)e + e->target_offset;
1165 +#ifndef IPT_LIB_DIR
1166 +#define IPT_LIB_DIR "/usr/local/lib/iptables"
1169 static int sockfd = -1;
1170 +static int sockfd_use = 0;
1171 static void *iptc_fn = NULL;
1173 static const char *hooknames[]
1178 +/* Convenience structures */
1179 +struct ipt_error_target
1181 + STRUCT_ENTRY_TARGET t;
1182 + char error[TABLE_MAXNAMELEN];
1192 unsigned int mappos;
1195 -/* Convenience structures */
1196 -struct ipt_error_target
1197 +enum iptcc_rule_type {
1198 + IPTCC_R_STANDARD, /* standard target (ACCEPT, ...) */
1199 + IPTCC_R_MODULE, /* extension module (SNAT, ...) */
1200 + IPTCC_R_FALLTHROUGH, /* fallthrough rule */
1201 + IPTCC_R_JUMP, /* jump to other chain */
1206 - STRUCT_ENTRY_TARGET t;
1207 - char error[TABLE_MAXNAMELEN];
1208 + struct list_head list;
1209 + struct chain_head *chain;
1210 + struct counter_map counter_map;
1212 + unsigned int index; /* index (needed for counter_map) */
1213 + unsigned int offset; /* offset in rule blob */
1215 + enum iptcc_rule_type type;
1216 + struct chain_head *jump; /* jump target, if IPTCC_R_JUMP */
1218 + unsigned int size; /* size of entry data */
1219 + STRUCT_ENTRY entry[0];
1225 + struct list_head list;
1226 char name[TABLE_MAXNAMELEN];
1227 - /* This is the first rule in chain. */
1228 - STRUCT_ENTRY *start;
1229 - /* Last rule in chain */
1230 - STRUCT_ENTRY *end;
1231 + unsigned int hooknum; /* hook number+1 if builtin */
1232 + unsigned int references; /* how many jumps reference us */
1233 + int verdict; /* verdict if builtin */
1235 + STRUCT_COUNTERS counters; /* per-chain counters */
1236 + struct counter_map counter_map;
1238 + unsigned int num_rules; /* number of rules in list */
1239 + struct list_head rules; /* list of rules */
1241 + unsigned int index; /* index (needed for jump resolval) */
1242 + unsigned int head_offset; /* offset in rule blob */
1243 + unsigned int foot_index; /* index (needed for counter_map) */
1244 + unsigned int foot_offset; /* offset in rule blob */
1249 - /* Have changes been made? */
1251 - /* Size in here reflects original state. */
1252 - STRUCT_GETINFO info;
1253 + int changed; /* Have changes been made? */
1255 + struct list_head chains;
1257 + struct chain_head *chain_iterator_cur;
1258 + struct rule_head *rule_iterator_cur;
1260 - struct counter_map *counter_map;
1261 - /* Array of hook names */
1262 - const char **hooknames;
1264 - /* Cached position of chain heads (NULL = no cache). */
1265 - unsigned int cache_num_chains;
1266 - unsigned int cache_num_builtins;
1267 - struct chain_cache *cache_chain_heads;
1269 - /* Chain iterator: current chain cache entry. */
1270 - struct chain_cache *cache_chain_iteration;
1272 - /* Rule iterator: terminal rule */
1273 - STRUCT_ENTRY *cache_rule_end;
1275 - /* Number in here reflects current state. */
1276 - unsigned int new_number;
1277 - STRUCT_GET_ENTRIES entries;
1278 + STRUCT_GETINFO info;
1279 + STRUCT_GET_ENTRIES *entries;
1282 +/* allocate a new chain head for the cache */
1283 +static struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
1285 + struct chain_head *c = malloc(sizeof(*c));
1288 + memset(c, 0, sizeof(*c));
1290 + strncpy(c->name, name, TABLE_MAXNAMELEN);
1291 + c->hooknum = hooknum;
1292 + INIT_LIST_HEAD(&c->rules);
1297 +/* allocate and initialize a new rule for the cache */
1298 +static struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int size)
1300 + struct rule_head *r = malloc(sizeof(*r)+size);
1303 + memset(r, 0, sizeof(*r));
1311 +/* notify us that the ruleset has been modified by the user */
1313 set_changed(TC_HANDLE_T h)
1315 - if (h->cache_chain_heads) {
1316 - free(h->cache_chain_heads);
1317 - h->cache_chain_heads = NULL;
1318 - h->cache_num_chains = 0;
1319 - h->cache_chain_iteration = NULL;
1320 - h->cache_rule_end = NULL;
1325 @@ -111,8 +179,13 @@
1330 +/**********************************************************************
1331 + * iptc blob utility functions (iptcb_*)
1332 + **********************************************************************/
1335 -get_number(const STRUCT_ENTRY *i,
1336 +iptcb_get_number(const STRUCT_ENTRY *i,
1337 const STRUCT_ENTRY *seek,
1340 @@ -122,22 +195,8 @@
1344 -static unsigned int
1345 -entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
1347 - unsigned int pos = 0;
1349 - if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
1350 - get_number, seek, &pos) == 0) {
1351 - fprintf(stderr, "ERROR: offset %i not an entry!\n",
1352 - (char *)seek - (char *)h->entries.entrytable);
1359 -get_entry_n(STRUCT_ENTRY *i,
1360 +iptcb_get_entry_n(STRUCT_ENTRY *i,
1361 unsigned int number,
1364 @@ -150,51 +209,556 @@
1368 -static STRUCT_ENTRY *
1369 -index2entry(TC_HANDLE_T h, unsigned int index)
1370 +static inline STRUCT_ENTRY *
1371 +iptcb_get_entry(TC_HANDLE_T h, unsigned int offset)
1373 - unsigned int pos = 0;
1374 - STRUCT_ENTRY *ret = NULL;
1375 + return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset);
1378 - ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
1379 - get_entry_n, index, &pos, &ret);
1380 +static unsigned int
1381 +iptcb_entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
1383 + unsigned int pos = 0;
1386 + if (ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
1387 + iptcb_get_number, seek, &pos) == 0) {
1388 + fprintf(stderr, "ERROR: offset %u not an entry!\n",
1389 + (unsigned int)((char *)seek - (char *)h->entries->entrytable));
1395 static inline STRUCT_ENTRY *
1396 -get_entry(TC_HANDLE_T h, unsigned int offset)
1397 +iptcb_offset2entry(TC_HANDLE_T h, unsigned int offset)
1399 - return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset);
1400 + return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset);
1404 static inline unsigned long
1405 -entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
1406 +iptcb_entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
1408 - return (char *)e - (char *)h->entries.entrytable;
1409 + return (void *)e - (void *)h->entries->entrytable;
1412 -static unsigned long
1413 -index2offset(TC_HANDLE_T h, unsigned int index)
1414 +static inline unsigned int
1415 +iptcb_offset2index(const TC_HANDLE_T h, unsigned int offset)
1417 - return entry2offset(h, index2entry(h, index));
1418 + return iptcb_entry2index(h, iptcb_offset2entry(h, offset));
1421 -static const char *
1422 -get_errorlabel(TC_HANDLE_T h, unsigned int offset)
1423 +/* Returns 0 if not hook entry, else hooknumber + 1 */
1424 +static inline unsigned int
1425 +iptcb_ent_is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
1430 - e = get_entry(h, offset);
1431 - if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) != 0) {
1432 - fprintf(stderr, "ERROR: offset %u not an error node!\n",
1435 + for (i = 0; i < NUMHOOKS; i++) {
1436 + if ((h->info.valid_hooks & (1 << i))
1437 + && iptcb_get_entry(h, h->info.hook_entry[i]) == e)
1444 +/**********************************************************************
1445 + * iptc cache utility functions (iptcc_*)
1446 + **********************************************************************/
1448 +/* Is the given chain builtin (1) or user-defined (0) */
1449 +static unsigned int iptcc_is_builtin(struct chain_head *c)
1451 + return (c->hooknum ? 1 : 0);
1454 +/* Get a specific rule within a chain */
1455 +static struct rule_head *iptcc_get_rule_num(struct chain_head *c,
1456 + unsigned int rulenum)
1458 + struct rule_head *r;
1459 + unsigned int num = 0;
1461 + list_for_each_entry(r, &c->rules, list) {
1463 + if (num == rulenum)
1469 +/* Get a specific rule within a chain backwards */
1470 +static struct rule_head *iptcc_get_rule_num_reverse(struct chain_head *c,
1471 + unsigned int rulenum)
1473 + struct rule_head *r;
1474 + unsigned int num = 0;
1476 + list_for_each_entry_reverse(r, &c->rules, list) {
1478 + if (num == rulenum)
1484 +/* Returns chain head if found, otherwise NULL. */
1485 +static struct chain_head *
1486 +iptcc_find_chain_by_offset(TC_HANDLE_T handle, unsigned int offset)
1488 + struct list_head *pos;
1490 + if (list_empty(&handle->chains))
1493 + list_for_each(pos, &handle->chains) {
1494 + struct chain_head *c = list_entry(pos, struct chain_head, list);
1495 + if (offset >= c->head_offset && offset <= c->foot_offset)
1501 +/* Returns chain head if found, otherwise NULL. */
1502 +static struct chain_head *
1503 +iptcc_find_label(const char *name, TC_HANDLE_T handle)
1505 + struct list_head *pos;
1507 + if (list_empty(&handle->chains))
1510 + list_for_each(pos, &handle->chains) {
1511 + struct chain_head *c = list_entry(pos, struct chain_head, list);
1512 + if (!strcmp(c->name, name))
1519 +/* called when rule is to be removed from cache */
1520 +static void iptcc_delete_rule(struct rule_head *r)
1522 + DEBUGP("deleting rule %p (offset %u)\n", r, r->offset);
1523 + /* clean up reference count of called chain */
1524 + if (r->type == IPTCC_R_JUMP
1526 + r->jump->references--;
1528 + list_del(&r->list);
1533 +/**********************************************************************
1534 + * RULESET PARSER (blob -> cache)
1535 + **********************************************************************/
1537 +/* Delete policy rule of previous chain, since cache doesn't contain
1538 + * chain policy rules.
1539 + * WARNING: This function has ugly design and relies on a lot of context, only
1540 + * to be called from specific places within the parser */
1541 +static int __iptcc_p_del_policy(TC_HANDLE_T h, unsigned int num)
1543 + if (h->chain_iterator_cur) {
1544 + /* policy rule is last rule */
1545 + struct rule_head *pr = (struct rule_head *)
1546 + h->chain_iterator_cur->rules.prev;
1548 + /* save verdict */
1549 + h->chain_iterator_cur->verdict =
1550 + *(int *)GET_TARGET(pr->entry)->data;
1552 + /* save counter and counter_map information */
1553 + h->chain_iterator_cur->counter_map.maptype =
1554 + COUNTER_MAP_NORMAL_MAP;
1555 + h->chain_iterator_cur->counter_map.mappos = num-1;
1556 + memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters,
1557 + sizeof(h->chain_iterator_cur->counters));
1559 + /* foot_offset points to verdict rule */
1560 + h->chain_iterator_cur->foot_index = num;
1561 + h->chain_iterator_cur->foot_offset = pr->offset;
1563 + /* delete rule from cache */
1564 + iptcc_delete_rule(pr);
1565 + h->chain_iterator_cur->num_rules--;
1572 +/* alphabetically insert a chain into the list */
1573 +static inline void iptc_insert_chain(TC_HANDLE_T h, struct chain_head *c)
1575 + struct chain_head *tmp;
1577 + /* sort only user defined chains */
1578 + if (!c->hooknum) {
1579 + list_for_each_entry(tmp, &h->chains, list) {
1580 + if (strcmp(c->name, tmp->name) <= 0) {
1581 + list_add(&c->list, tmp->list.prev);
1587 + /* survived till end of list: add at tail */
1588 + list_add_tail(&c->list, &h->chains);
1591 +/* Another ugly helper function split out of cache_add_entry to make it less
1592 + * spaghetti code */
1593 +static void __iptcc_p_add_chain(TC_HANDLE_T h, struct chain_head *c,
1594 + unsigned int offset, unsigned int *num)
1596 + __iptcc_p_del_policy(h, *num);
1598 + c->head_offset = offset;
1601 + iptc_insert_chain(h, c);
1603 + h->chain_iterator_cur = c;
1606 +/* main parser function: add an entry from the blob to the cache */
1607 +static int cache_add_entry(STRUCT_ENTRY *e,
1609 + STRUCT_ENTRY **prev,
1610 + unsigned int *num)
1612 + unsigned int builtin;
1613 + unsigned int offset = (char *)e - (char *)h->entries->entrytable;
1615 + DEBUGP("entering...");
1617 + /* Last entry ("policy rule"). End it.*/
1618 + if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) {
1619 + /* This is the ERROR node at the end of the chain */
1620 + DEBUGP_C("%u:%u: end of table:\n", *num, offset);
1622 + __iptcc_p_del_policy(h, *num);
1624 + h->chain_iterator_cur = NULL;
1628 + /* We know this is the start of a new chain if it's an ERROR
1629 + * target, or a hook entry point */
1631 + if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
1632 + struct chain_head *c =
1633 + iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0);
1634 + DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset,
1635 + (char *)c->name, c);
1641 + __iptcc_p_add_chain(h, c, offset, num);
1643 + } else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) {
1644 + struct chain_head *c =
1645 + iptcc_alloc_chain_head((char *)hooknames[builtin-1],
1647 + DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
1648 + *num, offset, c, &c->rules);
1654 + c->hooknum = builtin;
1656 + __iptcc_p_add_chain(h, c, offset, num);
1658 + /* FIXME: this is ugly. */
1661 + /* has to be normal rule */
1662 + struct rule_head *r;
1665 + if (!(r = iptcc_alloc_rule(h->chain_iterator_cur,
1666 + e->next_offset))) {
1670 + DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
1673 + r->offset = offset;
1674 + memcpy(r->entry, e, e->next_offset);
1675 + r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP;
1676 + r->counter_map.mappos = r->index;
1678 + /* handling of jumps, etc. */
1679 + if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) {
1680 + STRUCT_STANDARD_TARGET *t;
1682 + t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1683 + if (t->target.u.target_size
1684 + != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
1689 + if (t->verdict < 0) {
1690 + DEBUGP_C("standard, verdict=%d\n", t->verdict);
1691 + r->type = IPTCC_R_STANDARD;
1692 + } else if (t->verdict == r->offset+e->next_offset) {
1693 + DEBUGP_C("fallthrough\n");
1694 + r->type = IPTCC_R_FALLTHROUGH;
1696 + DEBUGP_C("jump, target=%u\n", t->verdict);
1697 + r->type = IPTCC_R_JUMP;
1698 + /* Jump target fixup has to be deferred
1699 + * until second pass, since we migh not
1700 + * yet have parsed the target */
1703 + DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name);
1704 + r->type = IPTCC_R_MODULE;
1707 + list_add_tail(&r->list, &h->chain_iterator_cur->rules);
1708 + h->chain_iterator_cur->num_rules++;
1716 +/* parse an iptables blob into it's pieces */
1717 +static int parse_table(TC_HANDLE_T h)
1719 + STRUCT_ENTRY *prev;
1720 + unsigned int num = 0;
1721 + struct chain_head *c;
1723 + /* First pass: over ruleset blob */
1724 + ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
1725 + cache_add_entry, h, &prev, &num);
1727 + /* Second pass: fixup parsed data from first pass */
1728 + list_for_each_entry(c, &h->chains, list) {
1729 + struct rule_head *r;
1730 + list_for_each_entry(r, &c->rules, list) {
1731 + struct chain_head *c;
1732 + STRUCT_STANDARD_TARGET *t;
1734 + if (r->type != IPTCC_R_JUMP)
1737 + t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
1738 + c = iptcc_find_chain_by_offset(h, t->verdict);
1746 + /* FIXME: sort chains */
1752 +/**********************************************************************
1753 + * RULESET COMPILATION (cache -> blob)
1754 + **********************************************************************/
1756 +/* Convenience structures */
1757 +struct iptcb_chain_start{
1759 + struct ipt_error_target name;
1761 +#define IPTCB_CHAIN_START_SIZE (sizeof(STRUCT_ENTRY) + \
1762 + ALIGN(sizeof(struct ipt_error_target)))
1764 +struct iptcb_chain_foot {
1766 + STRUCT_STANDARD_TARGET target;
1768 +#define IPTCB_CHAIN_FOOT_SIZE (sizeof(STRUCT_ENTRY) + \
1769 + ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
1771 +struct iptcb_chain_error {
1772 + STRUCT_ENTRY entry;
1773 + struct ipt_error_target target;
1775 +#define IPTCB_CHAIN_ERROR_SIZE (sizeof(STRUCT_ENTRY) + \
1776 + ALIGN(sizeof(struct ipt_error_target)))
1780 +/* compile rule from cache into blob */
1781 +static inline int iptcc_compile_rule (TC_HANDLE_T h, STRUCT_REPLACE *repl, struct rule_head *r)
1783 + /* handle jumps */
1784 + if (r->type == IPTCC_R_JUMP) {
1785 + STRUCT_STANDARD_TARGET *t;
1786 + t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
1787 + /* memset for memcmp convenience on delete/replace */
1788 + memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
1789 + strcpy(t->target.u.user.name, STANDARD_TARGET);
1790 + /* Jumps can only happen to builtin chains, so we
1791 + * can safely assume that they always have a header */
1792 + t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE;
1793 + } else if (r->type == IPTCC_R_FALLTHROUGH) {
1794 + STRUCT_STANDARD_TARGET *t;
1795 + t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
1796 + t->verdict = r->offset + r->size;
1799 + /* copy entry from cache to blob */
1800 + memcpy((char *)repl->entries+r->offset, r->entry, r->size);
1805 +/* compile chain from cache into blob */
1806 +static int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain_head *c)
1809 + struct rule_head *r;
1810 + struct iptcb_chain_start *head;
1811 + struct iptcb_chain_foot *foot;
1813 + /* only user-defined chains have heaer */
1814 + if (!iptcc_is_builtin(c)) {
1815 + /* put chain header in place */
1816 + head = (void *)repl->entries + c->head_offset;
1817 + head->e.target_offset = sizeof(STRUCT_ENTRY);
1818 + head->e.next_offset = IPTCB_CHAIN_START_SIZE;
1819 + strcpy(head->name.t.u.user.name, ERROR_TARGET);
1820 + head->name.t.u.target_size =
1821 + ALIGN(sizeof(struct ipt_error_target));
1822 + strcpy(head->name.error, c->name);
1824 + repl->hook_entry[c->hooknum-1] = c->head_offset;
1825 + repl->underflow[c->hooknum-1] = c->foot_offset;
1828 + /* iterate over rules */
1829 + list_for_each_entry(r, &c->rules, list) {
1830 + ret = iptcc_compile_rule(h, repl, r);
1835 + /* put chain footer in place */
1836 + foot = (void *)repl->entries + c->foot_offset;
1837 + foot->e.target_offset = sizeof(STRUCT_ENTRY);
1838 + foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE;
1839 + strcpy(foot->target.target.u.user.name, STANDARD_TARGET);
1840 + foot->target.target.u.target_size =
1841 + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1842 + /* builtin targets have verdict, others return */
1843 + if (iptcc_is_builtin(c))
1844 + foot->target.verdict = c->verdict;
1846 + foot->target.verdict = RETURN;
1847 + /* set policy-counters */
1848 + memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
1853 +/* calculate offset and number for every rule in the cache */
1854 +static int iptcc_compile_chain_offsets(TC_HANDLE_T h, struct chain_head *c,
1855 + int *offset, int *num)
1857 + struct rule_head *r;
1859 + c->head_offset = *offset;
1860 + DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset);
1862 + if (!iptcc_is_builtin(c)) {
1863 + /* Chain has header */
1864 + *offset += sizeof(STRUCT_ENTRY)
1865 + + ALIGN(sizeof(struct ipt_error_target));
1869 + list_for_each_entry(r, &c->rules, list) {
1870 + DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num);
1871 + r->offset = *offset;
1873 + *offset += r->size;
1877 + DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num,
1879 + c->foot_offset = *offset;
1880 + c->foot_index = *num;
1881 + *offset += sizeof(STRUCT_ENTRY)
1882 + + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1888 +/* put the pieces back together again */
1889 +static int iptcc_compile_table_prep(TC_HANDLE_T h, unsigned int *size)
1891 + struct chain_head *c;
1892 + unsigned int offset = 0, num = 0;
1895 + /* First pass: calculate offset for every rule */
1896 + list_for_each_entry(c, &h->chains, list) {
1897 + ret = iptcc_compile_chain_offsets(h, c, &offset, &num);
1902 - return (const char *)GET_TARGET(e)->data;
1903 + /* Append one error rule at end of chain */
1905 + offset += sizeof(STRUCT_ENTRY)
1906 + + ALIGN(sizeof(struct ipt_error_target));
1908 + /* ruleset size is now in offset */
1913 +static int iptcc_compile_table(TC_HANDLE_T h, STRUCT_REPLACE *repl)
1915 + struct chain_head *c;
1916 + struct iptcb_chain_error *error;
1918 + /* Second pass: copy from cache to offsets, fill in jumps */
1919 + list_for_each_entry(c, &h->chains, list) {
1920 + int ret = iptcc_compile_chain(h, repl, c);
1925 + /* Append error rule at end of chain */
1926 + error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE;
1927 + error->entry.target_offset = sizeof(STRUCT_ENTRY);
1928 + error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE;
1929 + error->target.t.u.user.target_size =
1930 + ALIGN(sizeof(struct ipt_error_target));
1931 + strcpy((char *)&error->target.t.u.user.name, ERROR_TARGET);
1932 + strcpy((char *)&error->target.error, "ERROR");
1937 +/**********************************************************************
1938 + * EXTERNAL API (operates on cache only)
1939 + **********************************************************************/
1941 /* Allocate handle of given size */
1943 alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
1944 @@ -202,94 +766,139 @@
1948 - len = sizeof(STRUCT_TC_HANDLE)
1950 - + num_rules * sizeof(struct counter_map);
1951 + len = sizeof(STRUCT_TC_HANDLE) + size;
1953 - if ((h = malloc(len)) == NULL) {
1954 + h = malloc(sizeof(STRUCT_TC_HANDLE));
1961 - h->cache_num_chains = 0;
1962 - h->cache_chain_heads = NULL;
1963 - h->counter_map = (void *)h
1964 - + sizeof(STRUCT_TC_HANDLE)
1966 + memset(h, 0, sizeof(*h));
1967 + INIT_LIST_HEAD(&h->chains);
1968 strcpy(h->info.name, tablename);
1969 - strcpy(h->entries.name, tablename);
1971 + h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size);
1973 + goto out_free_handle;
1975 + strcpy(h->entries->name, tablename);
1976 + h->entries->size = size;
1988 TC_INIT(const char *tablename)
1991 STRUCT_GETINFO info;
2000 + if (strlen(tablename) >= TABLE_MAXNAMELEN) {
2005 + if (sockfd_use == 0) {
2006 sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
2013 - if (strlen(tablename) >= TABLE_MAXNAMELEN) {
2018 strcpy(info.name, tablename);
2019 - if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)
2020 + if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) {
2021 + if (--sockfd_use == 0) {
2028 - if ((h = alloc_handle(info.name, info.size, info.num_entries))
2031 + DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
2032 + info.valid_hooks, info.num_entries, info.size);
2034 -/* Too hard --RR */
2036 - sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name);
2037 - dynlib = dlopen(pathname, RTLD_NOW);
2041 + if ((h = alloc_handle(info.name, info.size, info.num_entries))
2043 + if (--sockfd_use == 0) {
2047 - h->hooknames = dlsym(dynlib, "hooknames");
2048 - if (!h->hooknames) {
2053 - h->hooknames = hooknames;
2056 /* Initialize current state */
2058 - h->new_number = h->info.num_entries;
2059 - for (i = 0; i < h->info.num_entries; i++)
2061 - = ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i});
2063 - h->entries.size = h->info.size;
2064 + h->entries->size = h->info.size;
2066 tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
2068 - if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries,
2072 + if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
2078 + int fd = open("/tmp/libiptc-so_get_entries.blob",
2079 + O_CREAT|O_WRONLY);
2081 + write(fd, h->entries, tmp);
2087 + if (parse_table(h) < 0)
2093 + if (--sockfd_use == 0) {
2102 +TC_FREE(TC_HANDLE_T *h)
2104 + struct chain_head *c, *tmp;
2106 + iptc_fn = TC_FREE;
2107 + if (--sockfd_use == 0) {
2112 + list_for_each_entry_safe(c, tmp, &(*h)->chains, list) {
2113 + struct rule_head *r, *rtmp;
2115 + list_for_each_entry_safe(r, rtmp, &c->rules, list) {
2122 + free((*h)->entries);
2129 @@ -304,11 +913,11 @@
2131 TC_DUMP_ENTRIES(const TC_HANDLE_T handle)
2133 + iptc_fn = TC_DUMP_ENTRIES;
2136 - printf("libiptc v%s. %u entries, %u bytes.\n",
2137 - NETFILTER_VERSION,
2138 - handle->new_number, handle->entries.size);
2140 + printf("libiptc v%s. %u bytes.\n",
2141 + IPTABLES_VERSION, handle->entries->size);
2142 printf("Table `%s'\n", handle->info.name);
2143 printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
2144 handle->info.hook_entry[HOOK_PRE_ROUTING],
2145 @@ -323,516 +932,277 @@
2146 handle->info.underflow[HOOK_LOCAL_OUT],
2147 handle->info.underflow[HOOK_POST_ROUTING]);
2149 - ENTRY_ITERATE(handle->entries.entrytable, handle->entries.size,
2150 + ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size,
2151 dump_entry, handle);
2154 -/* Returns 0 if not hook entry, else hooknumber + 1 */
2155 -static inline unsigned int
2156 -is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
2160 - for (i = 0; i < NUMHOOKS; i++) {
2161 - if ((h->info.valid_hooks & (1 << i))
2162 - && get_entry(h, h->info.hook_entry[i]) == e)
2169 -add_chain(STRUCT_ENTRY *e, TC_HANDLE_T h, STRUCT_ENTRY **prev)
2171 - unsigned int builtin;
2173 - /* Last entry. End it. */
2174 - if (entry2offset(h, e) + e->next_offset == h->entries.size) {
2175 - /* This is the ERROR node at end of the table */
2176 - h->cache_chain_heads[h->cache_num_chains-1].end = *prev;
2180 - /* We know this is the start of a new chain if it's an ERROR
2181 - target, or a hook entry point */
2182 - if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
2183 - /* prev was last entry in previous chain */
2184 - h->cache_chain_heads[h->cache_num_chains-1].end
2187 - strcpy(h->cache_chain_heads[h->cache_num_chains].name,
2188 - (const char *)GET_TARGET(e)->data);
2189 - h->cache_chain_heads[h->cache_num_chains].start
2190 - = (void *)e + e->next_offset;
2191 - h->cache_num_chains++;
2192 - } else if ((builtin = is_hook_entry(e, h)) != 0) {
2193 - if (h->cache_num_chains > 0)
2194 - /* prev was last entry in previous chain */
2195 - h->cache_chain_heads[h->cache_num_chains-1].end
2198 - strcpy(h->cache_chain_heads[h->cache_num_chains].name,
2199 - h->hooknames[builtin-1]);
2200 - h->cache_chain_heads[h->cache_num_chains].start
2202 - h->cache_num_chains++;
2209 -static int alphasort(const void *a, const void *b)
2211 - return strcmp(((struct chain_cache *)a)->name,
2212 - ((struct chain_cache *)b)->name);
2215 -static int populate_cache(TC_HANDLE_T h)
2218 - STRUCT_ENTRY *prev;
2220 - /* # chains < # rules / 2 + num builtins - 1 */
2221 - h->cache_chain_heads = malloc((h->new_number / 2 + 4)
2222 - * sizeof(struct chain_cache));
2223 - if (!h->cache_chain_heads) {
2228 - h->cache_num_chains = 0;
2229 - h->cache_num_builtins = 0;
2231 - /* Count builtins */
2232 - for (i = 0; i < NUMHOOKS; i++) {
2233 - if (h->info.valid_hooks & (1 << i))
2234 - h->cache_num_builtins++;
2238 - ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
2239 - add_chain, h, &prev);
2241 - qsort(h->cache_chain_heads + h->cache_num_builtins,
2242 - h->cache_num_chains - h->cache_num_builtins,
2243 - sizeof(struct chain_cache), alphasort);
2248 -/* Returns cache ptr if found, otherwise NULL. */
2249 -static struct chain_cache *
2250 -find_label(const char *name, TC_HANDLE_T handle)
2254 - if (handle->cache_chain_heads == NULL
2255 - && !populate_cache(handle))
2258 - /* FIXME: Linear search through builtins, then binary --RR */
2259 - for (i = 0; i < handle->cache_num_chains; i++) {
2260 - if (strcmp(handle->cache_chain_heads[i].name, name) == 0)
2261 - return &handle->cache_chain_heads[i];
2268 /* Does this chain exist? */
2269 int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
2271 - return find_label(chain, handle) != NULL;
2272 + iptc_fn = TC_IS_CHAIN;
2273 + return iptcc_find_label(chain, handle) != NULL;
2276 -/* Returns the position of the final (ie. unconditional) element. */
2277 -static unsigned int
2278 -get_chain_end(const TC_HANDLE_T handle, unsigned int start)
2279 +static void iptcc_chain_iterator_advance(TC_HANDLE_T handle)
2281 - unsigned int last_off, off;
2285 - e = get_entry(handle, start);
2287 - /* Terminate when we meet a error label or a hook entry. */
2288 - for (off = start + e->next_offset;
2289 - off < handle->entries.size;
2290 - last_off = off, off += e->next_offset) {
2291 - STRUCT_ENTRY_TARGET *t;
2294 - e = get_entry(handle, off);
2296 - /* We hit an entry point. */
2297 - for (i = 0; i < NUMHOOKS; i++) {
2298 - if ((handle->info.valid_hooks & (1 << i))
2299 - && off == handle->info.hook_entry[i])
2302 + struct chain_head *c = handle->chain_iterator_cur;
2304 - /* We hit a user chain label */
2305 - t = GET_TARGET(e);
2306 - if (strcmp(t->u.user.name, ERROR_TARGET) == 0)
2309 - /* SHOULD NEVER HAPPEN */
2310 - fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n",
2311 - handle->entries.size, off);
2313 + if (c->list.next == &handle->chains)
2314 + handle->chain_iterator_cur = NULL;
2316 + handle->chain_iterator_cur =
2317 + list_entry(c->list.next, struct chain_head, list);
2320 /* Iterator functions to run through the chains. */
2322 TC_FIRST_CHAIN(TC_HANDLE_T *handle)
2324 - if ((*handle)->cache_chain_heads == NULL
2325 - && !populate_cache(*handle))
2326 + struct chain_head *c = list_entry((*handle)->chains.next,
2327 + struct chain_head, list);
2329 + iptc_fn = TC_FIRST_CHAIN;
2332 + if (list_empty(&(*handle)->chains)) {
2333 + DEBUGP(": no chains\n");
2337 - (*handle)->cache_chain_iteration
2338 - = &(*handle)->cache_chain_heads[0];
2339 + (*handle)->chain_iterator_cur = c;
2340 + iptcc_chain_iterator_advance(*handle);
2342 - return (*handle)->cache_chain_iteration->name;
2343 + DEBUGP(": returning `%s'\n", c->name);
2347 /* Iterator functions to run through the chains. Returns NULL at end. */
2349 TC_NEXT_CHAIN(TC_HANDLE_T *handle)
2351 - (*handle)->cache_chain_iteration++;
2352 + struct chain_head *c = (*handle)->chain_iterator_cur;
2354 - if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads
2355 - == (*handle)->cache_num_chains)
2356 + iptc_fn = TC_NEXT_CHAIN;
2359 + DEBUGP(": no more chains\n");
2363 - return (*handle)->cache_chain_iteration->name;
2364 + iptcc_chain_iterator_advance(*handle);
2366 + DEBUGP(": returning `%s'\n", c->name);
2370 /* Get first rule in the given chain: NULL for empty chain. */
2371 const STRUCT_ENTRY *
2372 TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
2374 - struct chain_cache *c;
2375 + struct chain_head *c;
2376 + struct rule_head *r;
2378 + iptc_fn = TC_FIRST_RULE;
2380 + DEBUGP("first rule(%s): ", chain);
2382 - c = find_label(chain, *handle);
2383 + c = iptcc_find_label(chain, *handle);
2389 /* Empty chain: single return/policy rule */
2390 - if (c->start == c->end)
2391 + if (list_empty(&c->rules)) {
2392 + DEBUGP_C("no rules, returning NULL\n");
2396 + r = list_entry(c->rules.next, struct rule_head, list);
2397 + (*handle)->rule_iterator_cur = r;
2398 + DEBUGP_C("%p\n", r);
2400 - (*handle)->cache_rule_end = c->end;
2405 /* Returns NULL when rules run out. */
2406 const STRUCT_ENTRY *
2407 TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
2409 - if ((void *)prev + prev->next_offset
2410 - == (void *)(*handle)->cache_rule_end)
2411 + struct rule_head *r;
2413 + iptc_fn = TC_NEXT_RULE;
2414 + DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
2416 + if (!(*handle)->rule_iterator_cur) {
2417 + DEBUGP_C("returning NULL\n");
2421 + r = list_entry((*handle)->rule_iterator_cur->list.next,
2422 + struct rule_head, list);
2424 + iptc_fn = TC_NEXT_RULE;
2426 + DEBUGP_C("next=%p, head=%p...", &r->list,
2427 + &(*handle)->rule_iterator_cur->chain->rules);
2429 + if (&r->list == &(*handle)->rule_iterator_cur->chain->rules) {
2430 + (*handle)->rule_iterator_cur = NULL;
2431 + DEBUGP_C("finished, returning NULL\n");
2435 + (*handle)->rule_iterator_cur = r;
2437 - return (void *)prev + prev->next_offset;
2438 + /* NOTE: prev is without any influence ! */
2439 + DEBUGP_C("returning rule %p\n", r);
2444 /* How many rules in this chain? */
2446 TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
2448 - unsigned int off = 0;
2449 - STRUCT_ENTRY *start, *end;
2451 + struct chain_head *c;
2452 + iptc_fn = TC_NUM_RULES;
2454 - if (!find_label(&off, chain, *handle)) {
2456 + c = iptcc_find_label(chain, *handle);
2459 return (unsigned int)-1;
2462 - start = get_entry(*handle, off);
2463 - end = get_entry(*handle, get_chain_end(*handle, off));
2465 - return entry2index(*handle, end) - entry2index(*handle, start);
2466 + return c->num_rules;
2469 -/* Get n'th rule in this chain. */
2470 const STRUCT_ENTRY *TC_GET_RULE(const char *chain,
2472 TC_HANDLE_T *handle)
2474 - unsigned int pos = 0, chainindex;
2475 + struct chain_head *c;
2476 + struct rule_head *r;
2478 + iptc_fn = TC_GET_RULE;
2481 - if (!find_label(&pos, chain, *handle)) {
2483 + c = iptcc_find_label(chain, *handle);
2489 - chainindex = entry2index(*handle, get_entry(*handle, pos));
2491 - return index2entry(*handle, chainindex + n);
2492 + r = iptcc_get_rule_num(c, n);
2499 -static const char *
2500 -target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce)
2501 +/* Returns a pointer to the target name of this position. */
2502 +const char *standard_target_map(int verdict)
2505 - unsigned int labelidx;
2506 - STRUCT_ENTRY *jumpto;
2508 - /* To avoid const warnings */
2509 - STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
2511 - if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0)
2512 - return GET_TARGET(e)->u.user.name;
2514 - /* Standard target: evaluate */
2515 - spos = *(int *)GET_TARGET(e)->data;
2517 - if (spos == RETURN)
2518 + switch (verdict) {
2520 return LABEL_RETURN;
2521 - else if (spos == -NF_ACCEPT-1)
2523 + case -NF_ACCEPT-1:
2524 return LABEL_ACCEPT;
2525 - else if (spos == -NF_DROP-1)
2529 - else if (spos == -NF_QUEUE-1)
2534 - fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n",
2535 - entry2offset(handle, e), handle->entries.size,
2539 + fprintf(stderr, "ERROR: %d not a valid target)\n",
2545 - jumpto = get_entry(handle, spos);
2547 - /* Fall through rule */
2548 - if (jumpto == (void *)e + e->next_offset)
2551 - /* Must point to head of a chain: ie. after error rule */
2552 - labelidx = entry2index(handle, jumpto) - 1;
2553 - return get_errorlabel(handle, index2offset(handle, labelidx));
2558 /* Returns a pointer to the target name of this position. */
2559 -const char *TC_GET_TARGET(const STRUCT_ENTRY *e,
2560 +const char *TC_GET_TARGET(const STRUCT_ENTRY *ce,
2561 TC_HANDLE_T *handle)
2563 - return target_name(*handle, e);
2564 + STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
2565 + struct rule_head *r = container_of(e, struct rule_head, entry[0]);
2567 + iptc_fn = TC_GET_TARGET;
2571 + case IPTCC_R_FALLTHROUGH:
2574 + case IPTCC_R_JUMP:
2575 + DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name);
2576 + return r->jump->name;
2578 + case IPTCC_R_STANDARD:
2579 + spos = *(int *)GET_TARGET(e)->data;
2580 + DEBUGP("r=%p, spos=%d'\n", r, spos);
2581 + return standard_target_map(spos);
2583 + case IPTCC_R_MODULE:
2584 + return GET_TARGET(e)->u.user.name;
2590 /* Is this a built-in chain? Actually returns hook + 1. */
2592 TC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
2595 + struct chain_head *c;
2597 - for (i = 0; i < NUMHOOKS; i++) {
2598 - if ((handle->info.valid_hooks & (1 << i))
2599 - && handle->hooknames[i]
2600 - && strcmp(handle->hooknames[i], chain) == 0)
2603 + iptc_fn = TC_BUILTIN;
2605 + c = iptcc_find_label(chain, handle);
2611 + return iptcc_is_builtin(c);
2614 /* Get the policy of a given built-in chain */
2616 TC_GET_POLICY(const char *chain,
2617 STRUCT_COUNTERS *counters,
2618 - TC_HANDLE_T *handle)
2620 - unsigned int start;
2624 - hook = TC_BUILTIN(chain, *handle);
2626 - start = (*handle)->info.hook_entry[hook-1];
2630 - e = get_entry(*handle, get_chain_end(*handle, start));
2631 - *counters = e->counters;
2633 - return target_name(*handle, e);
2637 -correct_verdict(STRUCT_ENTRY *e,
2639 - unsigned int offset, int delta_offset)
2641 - STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e);
2642 - unsigned int curr = (char *)e - base;
2644 - /* Trap: insert of fall-through rule. Don't change fall-through
2645 - verdict to jump-over-next-rule. */
2646 - if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0
2647 - && t->verdict > (int)offset
2648 - && !(curr == offset &&
2649 - t->verdict == curr + e->next_offset)) {
2650 - t->verdict += delta_offset;
2656 -/* Adjusts standard verdict jump positions after an insertion/deletion. */
2658 -set_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle)
2660 - ENTRY_ITERATE((*handle)->entries.entrytable,
2661 - (*handle)->entries.size,
2662 - correct_verdict, (char *)(*handle)->entries.entrytable,
2663 - offset, delta_offset);
2665 - set_changed(*handle);
2669 -/* If prepend is set, then we are prepending to a chain: if the
2670 - * insertion position is an entry point, keep the entry point. */
2672 -insert_rules(unsigned int num_rules, unsigned int rules_size,
2673 - const STRUCT_ENTRY *insert,
2674 - unsigned int offset, unsigned int num_rules_offset,
2676 TC_HANDLE_T *handle)
2679 - STRUCT_GETINFO newinfo;
2682 - if (offset >= (*handle)->entries.size) {
2686 + struct chain_head *c;
2688 - newinfo = (*handle)->info;
2690 - /* Fix up entry points. */
2691 - for (i = 0; i < NUMHOOKS; i++) {
2692 - /* Entry points to START of chain, so keep same if
2693 - inserting on at that point. */
2694 - if ((*handle)->info.hook_entry[i] > offset)
2695 - newinfo.hook_entry[i] += rules_size;
2697 - /* Underflow always points to END of chain (policy),
2698 - so if something is inserted at same point, it
2699 - should be advanced. */
2700 - if ((*handle)->info.underflow[i] >= offset)
2701 - newinfo.underflow[i] += rules_size;
2704 - newh = alloc_handle((*handle)->info.name,
2705 - (*handle)->entries.size + rules_size,
2706 - (*handle)->new_number + num_rules);
2709 - newh->info = newinfo;
2712 - memcpy(newh->entries.entrytable, (*handle)->entries.entrytable,offset);
2713 - /* ... Insert new ... */
2714 - memcpy((char *)newh->entries.entrytable + offset, insert, rules_size);
2715 - /* ... copy post */
2716 - memcpy((char *)newh->entries.entrytable + offset + rules_size,
2717 - (char *)(*handle)->entries.entrytable + offset,
2718 - (*handle)->entries.size - offset);
2720 - /* Move counter map. */
2722 - memcpy(newh->counter_map, (*handle)->counter_map,
2723 - sizeof(struct counter_map) * num_rules_offset);
2724 - /* ... copy post */
2725 - memcpy(newh->counter_map + num_rules_offset + num_rules,
2726 - (*handle)->counter_map + num_rules_offset,
2727 - sizeof(struct counter_map) * ((*handle)->new_number
2728 - - num_rules_offset));
2729 - /* Set intermediates to no counter copy */
2730 - for (i = 0; i < num_rules; i++)
2731 - newh->counter_map[num_rules_offset+i]
2732 - = ((struct counter_map){ COUNTER_MAP_SET, 0 });
2734 - newh->new_number = (*handle)->new_number + num_rules;
2735 - newh->entries.size = (*handle)->entries.size + rules_size;
2736 - newh->hooknames = (*handle)->hooknames;
2738 - if ((*handle)->cache_chain_heads)
2739 - free((*handle)->cache_chain_heads);
2743 - return set_verdict(offset, rules_size, handle);
2747 -delete_rules(unsigned int num_rules, unsigned int rules_size,
2748 - unsigned int offset, unsigned int num_rules_offset,
2749 - TC_HANDLE_T *handle)
2752 + iptc_fn = TC_GET_POLICY;
2754 - if (offset + rules_size > (*handle)->entries.size) {
2758 + DEBUGP("called for chain %s\n", chain);
2760 - /* Fix up entry points. */
2761 - for (i = 0; i < NUMHOOKS; i++) {
2762 - /* In practice, we never delete up to a hook entry,
2763 - since the built-in chains are always first,
2764 - so these two are never equal */
2765 - if ((*handle)->info.hook_entry[i] >= offset + rules_size)
2766 - (*handle)->info.hook_entry[i] -= rules_size;
2767 - else if ((*handle)->info.hook_entry[i] > offset) {
2768 - fprintf(stderr, "ERROR: Deleting entry %u %u %u\n",
2769 - i, (*handle)->info.hook_entry[i], offset);
2771 + c = iptcc_find_label(chain, *handle);
2777 - /* Underflow points to policy (terminal) rule in
2778 - built-in, so sequality is valid here (when deleting
2779 - the last rule). */
2780 - if ((*handle)->info.underflow[i] >= offset + rules_size)
2781 - (*handle)->info.underflow[i] -= rules_size;
2782 - else if ((*handle)->info.underflow[i] > offset) {
2783 - fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n",
2784 - i, (*handle)->info.underflow[i], offset);
2788 + if (!iptcc_is_builtin(c))
2791 - /* Move the rules down. */
2792 - memmove((char *)(*handle)->entries.entrytable + offset,
2793 - (char *)(*handle)->entries.entrytable + offset + rules_size,
2794 - (*handle)->entries.size - (offset + rules_size));
2796 - /* Move the counter map down. */
2797 - memmove(&(*handle)->counter_map[num_rules_offset],
2798 - &(*handle)->counter_map[num_rules_offset + num_rules],
2799 - sizeof(struct counter_map)
2800 - * ((*handle)->new_number - (num_rules + num_rules_offset)));
2803 - (*handle)->new_number -= num_rules;
2804 - (*handle)->entries.size -= rules_size;
2805 + *counters = c->counters;
2807 - return set_verdict(offset, -(int)rules_size, handle);
2808 + return standard_target_map(c->verdict);
2812 -standard_map(STRUCT_ENTRY *e, int verdict)
2813 +iptcc_standard_map(struct rule_head *r, int verdict)
2815 + STRUCT_ENTRY *e = r->entry;
2816 STRUCT_STANDARD_TARGET *t;
2818 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
2819 @@ -847,64 +1217,62 @@
2820 strcpy(t->target.u.user.name, STANDARD_TARGET);
2821 t->verdict = verdict;
2823 + r->type = IPTCC_R_STANDARD;
2829 -map_target(const TC_HANDLE_T handle,
2831 - unsigned int offset,
2832 - STRUCT_ENTRY_TARGET *old)
2833 +iptcc_map_target(const TC_HANDLE_T handle,
2834 + struct rule_head *r)
2836 + STRUCT_ENTRY *e = r->entry;
2837 STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
2839 - /* Save old target (except data, which we don't change, except for
2840 - standard case, where we don't care). */
2843 /* Maybe it's empty (=> fall through) */
2844 - if (strcmp(t->u.user.name, "") == 0)
2845 - return standard_map(e, offset + e->next_offset);
2846 + if (strcmp(t->u.user.name, "") == 0) {
2847 + r->type = IPTCC_R_FALLTHROUGH;
2850 /* Maybe it's a standard target name... */
2851 else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
2852 - return standard_map(e, -NF_ACCEPT - 1);
2853 + return iptcc_standard_map(r, -NF_ACCEPT - 1);
2854 else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
2855 - return standard_map(e, -NF_DROP - 1);
2856 + return iptcc_standard_map(r, -NF_DROP - 1);
2857 else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
2858 - return standard_map(e, -NF_QUEUE - 1);
2859 + return iptcc_standard_map(r, -NF_QUEUE - 1);
2860 else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
2861 - return standard_map(e, RETURN);
2862 + return iptcc_standard_map(r, RETURN);
2863 else if (TC_BUILTIN(t->u.user.name, handle)) {
2864 /* Can't jump to builtins. */
2868 /* Maybe it's an existing chain name. */
2869 - struct chain_cache *c;
2870 + struct chain_head *c;
2871 + DEBUGP("trying to find chain `%s': ", t->u.user.name);
2873 - c = find_label(t->u.user.name, handle);
2875 - return standard_map(e, entry2offset(handle, c->start));
2876 + c = iptcc_find_label(t->u.user.name, handle);
2878 + DEBUGP_C("found!\n");
2879 + r->type = IPTCC_R_JUMP;
2884 + DEBUGP_C("not found :(\n");
2887 /* Must be a module? If not, kernel will reject... */
2888 - /* memset to all 0 for your memcmp convenience. */
2889 + /* memset to all 0 for your memcmp convenience: don't clear version */
2890 memset(t->u.user.name + strlen(t->u.user.name),
2892 - FUNCTION_MAXNAMELEN - strlen(t->u.user.name));
2893 + FUNCTION_MAXNAMELEN - 1 - strlen(t->u.user.name));
2894 + r->type = IPTCC_R_MODULE;
2895 + set_changed(handle);
2900 -unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old)
2902 - STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
2904 - /* Save old target (except data, which we don't change, except for
2905 - standard case, where we don't care). */
2909 /* Insert the entry `fw' in chain `chain' into position `rulenum'. */
2911 TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
2912 @@ -912,36 +1280,56 @@
2913 unsigned int rulenum,
2914 TC_HANDLE_T *handle)
2916 - unsigned int chainindex, offset;
2917 - STRUCT_ENTRY_TARGET old;
2918 - struct chain_cache *c;
2919 - STRUCT_ENTRY *tmp;
2921 + struct chain_head *c;
2922 + struct rule_head *r;
2923 + struct list_head *prev;
2925 iptc_fn = TC_INSERT_ENTRY;
2926 - if (!(c = find_label(chain, *handle))) {
2928 + if (!(c = iptcc_find_label(chain, *handle))) {
2933 - chainindex = entry2index(*handle, c->start);
2935 - tmp = index2entry(*handle, chainindex + rulenum);
2936 - if (!tmp || tmp > c->end) {
2937 + /* first rulenum index = 0
2938 + first c->num_rules index = 1 */
2939 + if (rulenum > c->num_rules) {
2943 - offset = index2offset(*handle, chainindex + rulenum);
2945 - /* Mapping target actually alters entry, but that's
2946 - transparent to the caller. */
2947 - if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
2948 + /* If we are inserting at the end just take advantage of the
2949 + double linked list, insert will happen before the entry
2950 + prev points to. */
2951 + if (rulenum == c->num_rules) {
2953 + } else if (rulenum + 1 <= c->num_rules/2) {
2954 + r = iptcc_get_rule_num(c, rulenum + 1);
2957 + r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
2961 + if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
2966 + memcpy(r->entry, e, e->next_offset);
2967 + r->counter_map.maptype = COUNTER_MAP_SET;
2969 + if (!iptcc_map_target(*handle, r)) {
2974 + list_add_tail(&r->list, prev);
2977 + set_changed(*handle);
2979 - ret = insert_rules(1, e->next_offset, e, offset,
2980 - chainindex + rulenum, rulenum == 0, handle);
2981 - unmap_target((STRUCT_ENTRY *)e, &old);
2986 /* Atomically replace rule `rulenum' in `chain' with `fw'. */
2987 @@ -951,40 +1339,47 @@
2988 unsigned int rulenum,
2989 TC_HANDLE_T *handle)
2991 - unsigned int chainindex, offset;
2992 - STRUCT_ENTRY_TARGET old;
2993 - struct chain_cache *c;
2994 - STRUCT_ENTRY *tmp;
2996 + struct chain_head *c;
2997 + struct rule_head *r, *old;
2999 iptc_fn = TC_REPLACE_ENTRY;
3001 - if (!(c = find_label(chain, *handle))) {
3002 + if (!(c = iptcc_find_label(chain, *handle))) {
3007 - chainindex = entry2index(*handle, c->start);
3009 - tmp = index2entry(*handle, chainindex + rulenum);
3010 - if (!tmp || tmp >= c->end) {
3011 + if (rulenum >= c->num_rules) {
3016 - offset = index2offset(*handle, chainindex + rulenum);
3017 - /* Replace = delete and insert. */
3018 - if (!delete_rules(1, get_entry(*handle, offset)->next_offset,
3019 - offset, chainindex + rulenum, handle))
3020 + /* Take advantage of the double linked list if possible. */
3021 + if (rulenum + 1 <= c->num_rules/2) {
3022 + old = iptcc_get_rule_num(c, rulenum + 1);
3024 + old = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
3027 + if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
3032 - if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
3033 + memcpy(r->entry, e, e->next_offset);
3034 + r->counter_map.maptype = COUNTER_MAP_SET;
3036 + if (!iptcc_map_target(*handle, r)) {
3041 + list_add(&r->list, &old->list);
3042 + iptcc_delete_rule(old);
3044 + set_changed(*handle);
3046 - ret = insert_rules(1, e->next_offset, e, offset,
3047 - chainindex + rulenum, 1, handle);
3048 - unmap_target((STRUCT_ENTRY *)e, &old);
3053 /* Append entry `fw' to chain `chain'. Equivalent to insert with
3054 @@ -994,26 +1389,37 @@
3055 const STRUCT_ENTRY *e,
3056 TC_HANDLE_T *handle)
3058 - struct chain_cache *c;
3059 - STRUCT_ENTRY_TARGET old;
3061 + struct chain_head *c;
3062 + struct rule_head *r;
3064 iptc_fn = TC_APPEND_ENTRY;
3065 - if (!(c = find_label(chain, *handle))) {
3066 + if (!(c = iptcc_find_label(chain, *handle))) {
3067 + DEBUGP("unable to find chain `%s'\n", chain);
3072 - if (!map_target(*handle, (STRUCT_ENTRY *)e,
3073 - entry2offset(*handle, c->end), &old))
3074 + if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
3075 + DEBUGP("unable to allocate rule for chain `%s'\n", chain);
3080 + memcpy(r->entry, e, e->next_offset);
3081 + r->counter_map.maptype = COUNTER_MAP_SET;
3083 + if (!iptcc_map_target(*handle, r)) {
3084 + DEBUGP("unable to map target of rule for chain `%s'\n", chain);
3089 + list_add_tail(&r->list, &c->rules);
3092 + set_changed(*handle);
3094 - ret = insert_rules(1, e->next_offset, e,
3095 - entry2offset(*handle, c->end),
3096 - entry2index(*handle, c->end),
3098 - unmap_target((STRUCT_ENTRY *)e, &old);
3104 @@ -1044,20 +1450,42 @@
3108 -target_different(const unsigned char *a_targdata,
3109 - const unsigned char *b_targdata,
3110 - unsigned int tdatasize,
3111 - const unsigned char *mask)
3112 +target_same(struct rule_head *a, struct rule_head *b,const unsigned char *mask)
3115 - for (i = 0; i < tdatasize; i++)
3116 - if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
3117 + STRUCT_ENTRY_TARGET *ta, *tb;
3119 + if (a->type != b->type)
3122 + ta = GET_TARGET(a->entry);
3123 + tb = GET_TARGET(b->entry);
3125 + switch (a->type) {
3126 + case IPTCC_R_FALLTHROUGH:
3128 + case IPTCC_R_JUMP:
3129 + return a->jump == b->jump;
3130 + case IPTCC_R_STANDARD:
3131 + return ((STRUCT_STANDARD_TARGET *)ta)->verdict
3132 + == ((STRUCT_STANDARD_TARGET *)tb)->verdict;
3133 + case IPTCC_R_MODULE:
3134 + if (ta->u.target_size != tb->u.target_size)
3136 + if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
3139 + for (i = 0; i < ta->u.target_size - sizeof(*ta); i++)
3140 + if (((ta->data[i] ^ tb->data[i]) & mask[i]) != 0)
3144 + fprintf(stderr, "ERROR: bad type %i\n", a->type);
3150 +static unsigned char *
3151 is_same(const STRUCT_ENTRY *a,
3152 const STRUCT_ENTRY *b,
3153 unsigned char *matchmask);
3154 @@ -1069,88 +1497,106 @@
3155 unsigned char *matchmask,
3156 TC_HANDLE_T *handle)
3158 - unsigned int offset;
3159 - struct chain_cache *c;
3160 - STRUCT_ENTRY *e, *fw;
3161 + struct chain_head *c;
3162 + struct rule_head *r, *i;
3164 iptc_fn = TC_DELETE_ENTRY;
3165 - if (!(c = find_label(chain, *handle))) {
3166 + if (!(c = iptcc_find_label(chain, *handle))) {
3171 - fw = malloc(origfw->next_offset);
3173 + /* Create a rule_head from origfw. */
3174 + r = iptcc_alloc_rule(c, origfw->next_offset);
3180 - for (offset = entry2offset(*handle, c->start);
3181 - offset < entry2offset(*handle, c->end);
3182 - offset += e->next_offset) {
3183 - STRUCT_ENTRY_TARGET discard;
3185 - memcpy(fw, origfw, origfw->next_offset);
3187 - /* FIXME: handle this in is_same --RR */
3188 - if (!map_target(*handle, fw, offset, &discard)) {
3190 + memcpy(r->entry, origfw, origfw->next_offset);
3191 + r->counter_map.maptype = COUNTER_MAP_NOMAP;
3192 + if (!iptcc_map_target(*handle, r)) {
3193 + DEBUGP("unable to map target of rule for chain `%s'\n", chain);
3197 - e = get_entry(*handle, offset);
3200 - printf("Deleting:\n");
3203 - if (is_same(e, fw, matchmask)) {
3205 - ret = delete_rules(1, e->next_offset,
3206 - offset, entry2index(*handle, e),
3210 + list_for_each_entry(i, &c->rules, list) {
3211 + unsigned char *mask;
3213 + mask = is_same(r->entry, i->entry, matchmask);
3217 + if (!target_same(r, i, mask))
3220 + /* If we are about to delete the rule that is the
3221 + * current iterator, move rule iterator back. next
3222 + * pointer will then point to real next node */
3223 + if (i == (*handle)->rule_iterator_cur) {
3224 + (*handle)->rule_iterator_cur =
3225 + list_entry((*handle)->rule_iterator_cur->list.prev,
3226 + struct rule_head, list);
3230 + iptcc_delete_rule(i);
3232 + set_changed(*handle);
3244 /* Delete the rule in position `rulenum' in `chain'. */
3246 TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
3247 unsigned int rulenum,
3248 TC_HANDLE_T *handle)
3250 - unsigned int index;
3253 - struct chain_cache *c;
3254 + struct chain_head *c;
3255 + struct rule_head *r;
3257 iptc_fn = TC_DELETE_NUM_ENTRY;
3258 - if (!(c = find_label(chain, *handle))) {
3260 + if (!(c = iptcc_find_label(chain, *handle))) {
3265 - index = entry2index(*handle, c->start) + rulenum;
3267 - if (index >= entry2index(*handle, c->end)) {
3268 + if (rulenum >= c->num_rules) {
3273 - e = index2entry(*handle, index);
3277 + /* Take advantage of the double linked list if possible. */
3278 + if (rulenum + 1 <= c->num_rules/2) {
3279 + r = iptcc_get_rule_num(c, rulenum + 1);
3281 + r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
3284 + /* If we are about to delete the rule that is the current
3285 + * iterator, move rule iterator back. next pointer will then
3286 + * point to real next node */
3287 + if (r == (*handle)->rule_iterator_cur) {
3288 + (*handle)->rule_iterator_cur =
3289 + list_entry((*handle)->rule_iterator_cur->list.prev,
3290 + struct rule_head, list);
3293 - ret = delete_rules(1, e->next_offset, entry2offset(*handle, e),
3297 + iptcc_delete_rule(r);
3299 + set_changed(*handle);
3304 /* Check the packet `fw' on chain `chain'. Returns the verdict, or
3305 @@ -1160,6 +1606,7 @@
3306 STRUCT_ENTRY *entry,
3307 TC_HANDLE_T *handle)
3309 + iptc_fn = TC_CHECK_PACKET;
3313 @@ -1168,44 +1615,44 @@
3315 TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
3317 - unsigned int startindex, endindex;
3318 - struct chain_cache *c;
3320 + struct chain_head *c;
3321 + struct rule_head *r, *tmp;
3323 iptc_fn = TC_FLUSH_ENTRIES;
3324 - if (!(c = find_label(chain, *handle))) {
3325 + if (!(c = iptcc_find_label(chain, *handle))) {
3329 - startindex = entry2index(*handle, c->start);
3330 - endindex = entry2index(*handle, c->end);
3332 - ret = delete_rules(endindex - startindex,
3333 - (char *)c->end - (char *)c->start,
3334 - entry2offset(*handle, c->start), startindex,
3337 + list_for_each_entry_safe(r, tmp, &c->rules, list) {
3338 + iptcc_delete_rule(r);
3343 + set_changed(*handle);
3348 /* Zeroes the counters in a chain. */
3350 TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
3352 - unsigned int i, end;
3353 - struct chain_cache *c;
3354 + struct chain_head *c;
3355 + struct rule_head *r;
3357 - if (!(c = find_label(chain, *handle))) {
3358 + iptc_fn = TC_ZERO_ENTRIES;
3359 + if (!(c = iptcc_find_label(chain, *handle))) {
3364 - i = entry2index(*handle, c->start);
3365 - end = entry2index(*handle, c->end);
3367 - for (; i <= end; i++) {
3368 - if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP)
3369 - (*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED;
3370 + list_for_each_entry(r, &c->rules, list) {
3371 + if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
3372 + r->counter_map.maptype = COUNTER_MAP_ZEROED;
3375 set_changed(*handle);
3378 @@ -1216,29 +1663,23 @@
3379 unsigned int rulenum,
3380 TC_HANDLE_T *handle)
3383 - struct chain_cache *c;
3384 - unsigned int chainindex, end;
3385 + struct chain_head *c;
3386 + struct rule_head *r;
3388 iptc_fn = TC_READ_COUNTER;
3391 - if (!(c = find_label(chain, *handle))) {
3392 + if (!(c = iptcc_find_label(chain, *handle))) {
3397 - chainindex = entry2index(*handle, c->start);
3398 - end = entry2index(*handle, c->end);
3400 - if (chainindex + rulenum > end) {
3401 + if (!(r = iptcc_get_rule_num(c, rulenum))) {
3406 - e = index2entry(*handle, chainindex + rulenum);
3408 - return &e->counters;
3409 + return &r->entry[0].counters;
3413 @@ -1246,33 +1687,24 @@
3414 unsigned int rulenum,
3415 TC_HANDLE_T *handle)
3418 - struct chain_cache *c;
3419 - unsigned int chainindex, end;
3420 + struct chain_head *c;
3421 + struct rule_head *r;
3423 iptc_fn = TC_ZERO_COUNTER;
3426 - if (!(c = find_label(chain, *handle))) {
3427 + if (!(c = iptcc_find_label(chain, *handle))) {
3432 - chainindex = entry2index(*handle, c->start);
3433 - end = entry2index(*handle, c->end);
3435 - if (chainindex + rulenum > end) {
3436 + if (!(r = iptcc_get_rule_num(c, rulenum))) {
3441 - e = index2entry(*handle, chainindex + rulenum);
3443 -// if ((*handle)->counter_map[chainindex + rulenum].maptype
3444 -// == COUNTER_MAP_NORMAL_MAP) {
3445 - (*handle)->counter_map[chainindex + rulenum].maptype
3446 - = COUNTER_MAP_ZEROED;
3448 + if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
3449 + r->counter_map.maptype = COUNTER_MAP_ZEROED;
3451 set_changed(*handle);
3453 @@ -1285,30 +1717,25 @@
3454 STRUCT_COUNTERS *counters,
3455 TC_HANDLE_T *handle)
3457 + struct chain_head *c;
3458 + struct rule_head *r;
3460 - struct chain_cache *c;
3461 - unsigned int chainindex, end;
3463 iptc_fn = TC_SET_COUNTER;
3466 - if (!(c = find_label(chain, *handle))) {
3467 + if (!(c = iptcc_find_label(chain, *handle))) {
3472 - chainindex = entry2index(*handle, c->start);
3473 - end = entry2index(*handle, c->end);
3475 - if (chainindex + rulenum > end) {
3476 + if (!(r = iptcc_get_rule_num(c, rulenum))) {
3481 - e = index2entry(*handle, chainindex + rulenum);
3483 - (*handle)->counter_map[chainindex + rulenum].maptype
3484 - = COUNTER_MAP_SET;
3486 + r->counter_map.maptype = COUNTER_MAP_SET;
3488 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
3490 @@ -1323,71 +1750,42 @@
3492 TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
3496 - STRUCT_ENTRY head;
3497 - struct ipt_error_target name;
3499 - STRUCT_STANDARD_TARGET target;
3501 + static struct chain_head *c;
3503 iptc_fn = TC_CREATE_CHAIN;
3505 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
3507 - if (find_label(chain, *handle)
3508 + if (iptcc_find_label(chain, *handle)
3509 || strcmp(chain, LABEL_DROP) == 0
3510 || strcmp(chain, LABEL_ACCEPT) == 0
3511 || strcmp(chain, LABEL_QUEUE) == 0
3512 || strcmp(chain, LABEL_RETURN) == 0) {
3513 + DEBUGP("Chain `%s' already exists\n", chain);
3518 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
3519 + DEBUGP("Chain name `%s' too long\n", chain);
3524 - memset(&newc, 0, sizeof(newc));
3525 - newc.head.target_offset = sizeof(STRUCT_ENTRY);
3526 - newc.head.next_offset
3527 - = sizeof(STRUCT_ENTRY)
3528 - + ALIGN(sizeof(struct ipt_error_target));
3529 - strcpy(newc.name.t.u.user.name, ERROR_TARGET);
3530 - newc.name.t.u.target_size = ALIGN(sizeof(struct ipt_error_target));
3531 - strcpy(newc.name.error, chain);
3533 - newc.ret.target_offset = sizeof(STRUCT_ENTRY);
3534 - newc.ret.next_offset
3535 - = sizeof(STRUCT_ENTRY)
3536 - + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
3537 - strcpy(newc.target.target.u.user.name, STANDARD_TARGET);
3538 - newc.target.target.u.target_size
3539 - = ALIGN(sizeof(STRUCT_STANDARD_TARGET));
3540 - newc.target.verdict = RETURN;
3542 - /* Add just before terminal entry */
3543 - ret = insert_rules(2, sizeof(newc), &newc.head,
3544 - index2offset(*handle, (*handle)->new_number - 1),
3545 - (*handle)->new_number - 1,
3549 + c = iptcc_alloc_chain_head(chain, 0);
3551 + DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
3556 -count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref)
3558 - STRUCT_STANDARD_TARGET *t;
3561 - if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) == 0) {
3562 - t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
3563 + DEBUGP("Creating chain `%s'\n", chain);
3564 + list_add_tail(&c->list, &(*handle)->chains);
3566 - if (t->verdict == offset)
3569 + set_changed(*handle);
3575 /* Get the number of references to this chain. */
3576 @@ -1395,17 +1793,16 @@
3577 TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
3578 TC_HANDLE_T *handle)
3580 - struct chain_cache *c;
3581 + struct chain_head *c;
3583 - if (!(c = find_label(chain, *handle))) {
3584 + iptc_fn = TC_GET_REFERENCES;
3585 + if (!(c = iptcc_find_label(chain, *handle))) {
3591 - ENTRY_ITERATE((*handle)->entries.entrytable,
3592 - (*handle)->entries.size,
3593 - count_ref, entry2offset(*handle, c->start), ref);
3594 + *ref = c->references;
3599 @@ -1413,45 +1810,53 @@
3601 TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
3603 - unsigned int labelidx, labeloff;
3604 unsigned int references;
3605 - struct chain_cache *c;
3608 - if (!TC_GET_REFERENCES(&references, chain, handle))
3610 + struct chain_head *c;
3612 iptc_fn = TC_DELETE_CHAIN;
3614 + if (!(c = iptcc_find_label(chain, *handle))) {
3615 + DEBUGP("cannot find chain `%s'\n", chain);
3620 if (TC_BUILTIN(chain, *handle)) {
3621 + DEBUGP("cannot remove builtin chain `%s'\n", chain);
3626 - if (references > 0) {
3628 + if (!TC_GET_REFERENCES(&references, chain, handle)) {
3629 + DEBUGP("cannot get references on chain `%s'\n", chain);
3633 - if (!(c = find_label(chain, *handle))) {
3635 + if (references > 0) {
3636 + DEBUGP("chain `%s' still has references\n", chain);
3641 - if ((void *)c->start != c->end) {
3642 + if (c->num_rules) {
3643 + DEBUGP("chain `%s' is not empty\n", chain);
3648 - /* Need label index: preceeds chain start */
3649 - labelidx = entry2index(*handle, c->start) - 1;
3650 - labeloff = index2offset(*handle, labelidx);
3652 - ret = delete_rules(2,
3653 - get_entry(*handle, labeloff)->next_offset
3654 - + c->start->next_offset,
3655 - labeloff, labelidx, handle);
3657 + /* If we are about to delete the chain that is the current
3658 + * iterator, move chain iterator firward. */
3659 + if (c == (*handle)->chain_iterator_cur)
3660 + iptcc_chain_iterator_advance(*handle);
3662 + list_del(&c->list);
3665 + DEBUGP("chain `%s' deleted\n", chain);
3667 + set_changed(*handle);
3672 /* Renames a chain. */
3673 @@ -1459,15 +1864,12 @@
3674 const IPT_CHAINLABEL newname,
3675 TC_HANDLE_T *handle)
3677 - unsigned int labeloff, labelidx;
3678 - struct chain_cache *c;
3679 - struct ipt_error_target *t;
3681 + struct chain_head *c;
3682 iptc_fn = TC_RENAME_CHAIN;
3684 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
3686 - if (find_label(newname, *handle)
3687 + if (iptcc_find_label(newname, *handle)
3688 || strcmp(newname, LABEL_DROP) == 0
3689 || strcmp(newname, LABEL_ACCEPT) == 0
3690 || strcmp(newname, LABEL_QUEUE) == 0
3691 @@ -1476,7 +1878,7 @@
3695 - if (!(c = find_label(oldname, *handle))
3696 + if (!(c = iptcc_find_label(oldname, *handle))
3697 || TC_BUILTIN(oldname, *handle)) {
3700 @@ -1487,15 +1889,8 @@
3704 - /* Need label index: preceeds chain start */
3705 - labelidx = entry2index(*handle, c->start) - 1;
3706 - labeloff = index2offset(*handle, labelidx);
3707 + strncpy(c->name, newname, sizeof(IPT_CHAINLABEL));
3709 - t = (struct ipt_error_target *)
3710 - GET_TARGET(get_entry(*handle, labeloff));
3712 - memset(t->error, 0, sizeof(t->error));
3713 - strcpy(t->error, newname);
3714 set_changed(*handle);
3717 @@ -1508,51 +1903,37 @@
3718 STRUCT_COUNTERS *counters,
3719 TC_HANDLE_T *handle)
3721 - unsigned int hook;
3722 - unsigned int policyoff, ctrindex;
3724 - STRUCT_STANDARD_TARGET *t;
3725 + struct chain_head *c;
3727 iptc_fn = TC_SET_POLICY;
3728 - /* Figure out which chain. */
3729 - hook = TC_BUILTIN(chain, *handle);
3732 + if (!(c = iptcc_find_label(chain, *handle))) {
3733 + DEBUGP("cannot find chain `%s'\n", chain);
3740 - policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]);
3741 - if (policyoff != (*handle)->info.underflow[hook]) {
3742 - printf("ERROR: Policy for `%s' offset %u != underflow %u\n",
3743 - chain, policyoff, (*handle)->info.underflow[hook]);
3744 + if (!iptcc_is_builtin(c)) {
3745 + DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain);
3750 - e = get_entry(*handle, policyoff);
3751 - t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
3753 if (strcmp(policy, LABEL_ACCEPT) == 0)
3754 - t->verdict = -NF_ACCEPT - 1;
3755 + c->verdict = -NF_ACCEPT - 1;
3756 else if (strcmp(policy, LABEL_DROP) == 0)
3757 - t->verdict = -NF_DROP - 1;
3758 + c->verdict = -NF_DROP - 1;
3764 - ctrindex = entry2index(*handle, e);
3767 /* set byte and packet counters */
3768 - memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
3770 - (*handle)->counter_map[ctrindex].maptype
3771 - = COUNTER_MAP_SET;
3773 + memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS));
3774 + c->counter_map.maptype = COUNTER_MAP_SET;
3776 - (*handle)->counter_map[ctrindex]
3777 - = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
3778 + c->counter_map.maptype = COUNTER_MAP_NOMAP;
3781 set_changed(*handle);
3782 @@ -1575,31 +1956,100 @@
3783 answer->bcnt = a->bcnt - b->bcnt;
3787 +static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters,
3788 + unsigned int index)
3790 + newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0});
3791 + DEBUGP_C("NOMAP => zero\n");
3794 +static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
3795 + STRUCT_REPLACE *repl,
3796 + unsigned int index,
3797 + unsigned int mappos)
3799 + /* Original read: X.
3800 + * Atomic read on replacement: X + Y.
3801 + * Currently in kernel: Z.
3802 + * Want in kernel: X + Y + Z.
3804 + * => Add in replacement read.
3806 + newcounters->counters[index] = repl->counters[mappos];
3807 + DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
3810 +static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
3811 + STRUCT_REPLACE *repl,
3812 + unsigned int index,
3813 + unsigned int mappos,
3814 + STRUCT_COUNTERS *counters)
3816 + /* Original read: X.
3817 + * Atomic read on replacement: X + Y.
3818 + * Currently in kernel: Z.
3819 + * Want in kernel: Y + Z.
3821 + * => Add in (replacement read - original read).
3823 + subtract_counters(&newcounters->counters[index],
3824 + &repl->counters[mappos],
3826 + DEBUGP_C("ZEROED => mappos %u\n", mappos);
3829 +static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
3830 + unsigned int index,
3831 + STRUCT_COUNTERS *counters)
3833 + /* Want to set counter (iptables-restore) */
3835 + memcpy(&newcounters->counters[index], counters,
3836 + sizeof(STRUCT_COUNTERS));
3838 + DEBUGP_C("SET\n");
3843 TC_COMMIT(TC_HANDLE_T *handle)
3845 /* Replace, then map back the counters. */
3846 STRUCT_REPLACE *repl;
3847 STRUCT_COUNTERS_INFO *newcounters;
3850 - = sizeof(STRUCT_COUNTERS_INFO)
3851 - + sizeof(STRUCT_COUNTERS) * (*handle)->new_number;
3852 + struct chain_head *c;
3854 + size_t counterlen;
3856 + unsigned int new_size;
3858 + iptc_fn = TC_COMMIT;
3861 - TC_DUMP_ENTRIES(*handle);
3864 /* Don't commit if nothing changed. */
3865 if (!(*handle)->changed)
3868 - repl = malloc(sizeof(*repl) + (*handle)->entries.size);
3869 + new_number = iptcc_compile_table_prep(*handle, &new_size);
3870 + if (new_number < 0) {
3875 + repl = malloc(sizeof(*repl) + new_size);
3880 + memset(repl, 0, sizeof(*repl) + new_size);
3883 + TC_DUMP_ENTRIES(*handle);
3886 + counterlen = sizeof(STRUCT_COUNTERS_INFO)
3887 + + sizeof(STRUCT_COUNTERS) * new_number;
3889 /* These are the old counters we will get from kernel */
3890 repl->counters = malloc(sizeof(STRUCT_COUNTERS)
3891 @@ -1609,7 +2059,6 @@
3896 /* These are the counters we're going to put back, later. */
3897 newcounters = malloc(counterlen);
3899 @@ -1618,21 +2067,40 @@
3903 + memset(newcounters, 0, counterlen);
3905 strcpy(repl->name, (*handle)->info.name);
3906 - repl->num_entries = (*handle)->new_number;
3907 - repl->size = (*handle)->entries.size;
3908 - memcpy(repl->hook_entry, (*handle)->info.hook_entry,
3909 - sizeof(repl->hook_entry));
3910 - memcpy(repl->underflow, (*handle)->info.underflow,
3911 - sizeof(repl->underflow));
3912 + repl->num_entries = new_number;
3913 + repl->size = new_size;
3915 repl->num_counters = (*handle)->info.num_entries;
3916 repl->valid_hooks = (*handle)->info.valid_hooks;
3917 - memcpy(repl->entries, (*handle)->entries.entrytable,
3918 - (*handle)->entries.size);
3920 + DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
3921 + repl->num_entries, repl->size, repl->num_counters);
3923 + ret = iptcc_compile_table(*handle, repl);
3926 + free(repl->counters);
3934 + int fd = open("/tmp/libiptc-so_set_replace.blob",
3935 + O_CREAT|O_WRONLY);
3937 + write(fd, repl, sizeof(*repl) + repl->size);
3943 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
3944 - sizeof(*repl) + (*handle)->entries.size) < 0) {
3945 + sizeof(*repl) + repl->size) < 0) {
3946 free(repl->counters);
3949 @@ -1641,49 +2109,64 @@
3951 /* Put counters back. */
3952 strcpy(newcounters->name, (*handle)->info.name);
3953 - newcounters->num_counters = (*handle)->new_number;
3954 - for (i = 0; i < (*handle)->new_number; i++) {
3955 - unsigned int mappos = (*handle)->counter_map[i].mappos;
3956 - switch ((*handle)->counter_map[i].maptype) {
3957 + newcounters->num_counters = new_number;
3959 + list_for_each_entry(c, &(*handle)->chains, list) {
3960 + struct rule_head *r;
3962 + /* Builtin chains have their own counters */
3963 + if (iptcc_is_builtin(c)) {
3964 + DEBUGP("counter for chain-index %u: ", c->foot_index);
3965 + switch(c->counter_map.maptype) {
3966 + case COUNTER_MAP_NOMAP:
3967 + counters_nomap(newcounters, c->foot_index);
3969 + case COUNTER_MAP_NORMAL_MAP:
3970 + counters_normal_map(newcounters, repl,
3972 + c->counter_map.mappos);
3974 + case COUNTER_MAP_ZEROED:
3975 + counters_map_zeroed(newcounters, repl,
3977 + c->counter_map.mappos,
3980 + case COUNTER_MAP_SET:
3981 + counters_map_set(newcounters, c->foot_index,
3987 + list_for_each_entry(r, &c->rules, list) {
3988 + DEBUGP("counter for index %u: ", r->index);
3989 + switch (r->counter_map.maptype) {
3990 case COUNTER_MAP_NOMAP:
3991 - newcounters->counters[i]
3992 - = ((STRUCT_COUNTERS){ 0, 0 });
3993 + counters_nomap(newcounters, r->index);
3996 case COUNTER_MAP_NORMAL_MAP:
3997 - /* Original read: X.
3998 - * Atomic read on replacement: X + Y.
3999 - * Currently in kernel: Z.
4000 - * Want in kernel: X + Y + Z.
4002 - * => Add in replacement read.
4004 - newcounters->counters[i] = repl->counters[mappos];
4005 + counters_normal_map(newcounters, repl,
4007 + r->counter_map.mappos);
4010 case COUNTER_MAP_ZEROED:
4011 - /* Original read: X.
4012 - * Atomic read on replacement: X + Y.
4013 - * Currently in kernel: Z.
4014 - * Want in kernel: Y + Z.
4016 - * => Add in (replacement read - original read).
4018 - subtract_counters(&newcounters->counters[i],
4019 - &repl->counters[mappos],
4020 - &index2entry(*handle, i)->counters);
4021 + counters_map_zeroed(newcounters, repl,
4023 + r->counter_map.mappos,
4024 + &r->entry->counters);
4027 case COUNTER_MAP_SET:
4028 - /* Want to set counter (iptables-restore) */
4030 - memcpy(&newcounters->counters[i],
4031 - &index2entry(*handle, i)->counters,
4032 - sizeof(STRUCT_COUNTERS));
4034 + counters_map_set(newcounters, r->index,
4035 + &r->entry->counters);
4042 #ifdef KERNEL_64_USERSPACE_32
4044 @@ -1696,10 +2179,21 @@
4045 "counters alignment incorrect! Mail rusty!\n");
4048 - *kernptr = &newcounters->counters;
4049 + *kernptr = newcounters->counters;
4051 #endif /* KERNEL_64_USERSPACE_32 */
4055 + int fd = open("/tmp/libiptc-so_set_add_counters.blob",
4056 + O_CREAT|O_WRONLY);
4058 + write(fd, newcounters, counterlen);
4064 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
4065 newcounters, counterlen) < 0) {
4066 free(repl->counters);
4067 @@ -1713,10 +2207,7 @@
4071 - if ((*handle)->cache_chain_heads)
4072 - free((*handle)->cache_chain_heads);
4079 diff -Nur ipac-ng-1.31.orig/agents/iptables/libiptc.h ipac-ng-1.31/agents/iptables/libiptc.h
4080 --- ipac-ng-1.31.orig/agents/iptables/libiptc.h 2003-07-06 10:33:17.000000000 +0000
4081 +++ ipac-ng-1.31/agents/iptables/libiptc.h 2006-01-10 21:01:39.000000000 +0000
4083 -#ifndef NETFILTER_VERSION
4084 -#define NETFILTER_VERSION "1.2.5"
4089 /* Library which manipulates filtering rules. */
4091 /* Take a snapshot of the rules. Returns NULL on error. */
4092 iptc_handle_t iptc_init(const char *tablename);
4094 +/* Cleanup after iptc_init(). */
4095 +void iptc_free(iptc_handle_t *h);
4097 /* Iterator functions to run through the chains. Returns NULL at end. */
4098 const char *iptc_first_chain(iptc_handle_t *handle);
4099 const char *iptc_next_chain(iptc_handle_t *handle);
4100 diff -Nur ipac-ng-1.31.orig/agents/iptables/linux_list.h ipac-ng-1.31/agents/iptables/linux_list.h
4101 --- ipac-ng-1.31.orig/agents/iptables/linux_list.h 1970-01-01 00:00:00.000000000 +0000
4102 +++ ipac-ng-1.31/agents/iptables/linux_list.h 2006-01-10 21:01:39.000000000 +0000
4104 +#ifndef _LINUX_LIST_H
4105 +#define _LINUX_LIST_H
4108 +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
4111 + * container_of - cast a member of a structure out to the containing structure
4113 + * @ptr: the pointer to the member.
4114 + * @type: the type of the container struct this is embedded in.
4115 + * @member: the name of the member within the struct.
4118 +#define container_of(ptr, type, member) ({ \
4119 + const typeof( ((type *)0)->member ) *__mptr = (ptr); \
4120 + (type *)( (char *)__mptr - offsetof(type,member) );})
4123 + * Check at compile time that something is of a particular type.
4124 + * Always evaluates to 1 so you may use it easily in comparisons.
4126 +#define typecheck(type,x) \
4128 + typeof(x) __dummy2; \
4129 + (void)(&__dummy == &__dummy2); \
4133 +#define prefetch(x) 1
4135 +/* empty define to make this work in userspace -HW */
4139 + * These are non-NULL pointers that will result in page faults
4140 + * under normal circumstances, used to verify that nobody uses
4141 + * non-initialized list entries.
4143 +#define LIST_POISON1 ((void *) 0x00100100)
4144 +#define LIST_POISON2 ((void *) 0x00200200)
4147 + * Simple doubly linked list implementation.
4149 + * Some of the internal functions ("__xxx") are useful when
4150 + * manipulating whole lists rather than single entries, as
4151 + * sometimes we already know the next/prev entries and we can
4152 + * generate better code by using them directly rather than
4153 + * using the generic single-entry routines.
4157 + struct list_head *next, *prev;
4160 +#define LIST_HEAD_INIT(name) { &(name), &(name) }
4162 +#define LIST_HEAD(name) \
4163 + struct list_head name = LIST_HEAD_INIT(name)
4165 +#define INIT_LIST_HEAD(ptr) do { \
4166 + (ptr)->next = (ptr); (ptr)->prev = (ptr); \
4170 + * Insert a new entry between two known consecutive entries.
4172 + * This is only for internal list manipulation where we know
4173 + * the prev/next entries already!
4175 +static inline void __list_add(struct list_head *new,
4176 + struct list_head *prev,
4177 + struct list_head *next)
4186 + * list_add - add a new entry
4187 + * @new: new entry to be added
4188 + * @head: list head to add it after
4190 + * Insert a new entry after the specified head.
4191 + * This is good for implementing stacks.
4193 +static inline void list_add(struct list_head *new, struct list_head *head)
4195 + __list_add(new, head, head->next);
4199 + * list_add_tail - add a new entry
4200 + * @new: new entry to be added
4201 + * @head: list head to add it before
4203 + * Insert a new entry before the specified head.
4204 + * This is useful for implementing queues.
4206 +static inline void list_add_tail(struct list_head *new, struct list_head *head)
4208 + __list_add(new, head->prev, head);
4212 + * Insert a new entry between two known consecutive entries.
4214 + * This is only for internal list manipulation where we know
4215 + * the prev/next entries already!
4217 +static inline void __list_add_rcu(struct list_head * new,
4218 + struct list_head * prev, struct list_head * next)
4228 + * list_add_rcu - add a new entry to rcu-protected list
4229 + * @new: new entry to be added
4230 + * @head: list head to add it after
4232 + * Insert a new entry after the specified head.
4233 + * This is good for implementing stacks.
4235 + * The caller must take whatever precautions are necessary
4236 + * (such as holding appropriate locks) to avoid racing
4237 + * with another list-mutation primitive, such as list_add_rcu()
4238 + * or list_del_rcu(), running on this same list.
4239 + * However, it is perfectly legal to run concurrently with
4240 + * the _rcu list-traversal primitives, such as
4241 + * list_for_each_entry_rcu().
4243 +static inline void list_add_rcu(struct list_head *new, struct list_head *head)
4245 + __list_add_rcu(new, head, head->next);
4249 + * list_add_tail_rcu - add a new entry to rcu-protected list
4250 + * @new: new entry to be added
4251 + * @head: list head to add it before
4253 + * Insert a new entry before the specified head.
4254 + * This is useful for implementing queues.
4256 + * The caller must take whatever precautions are necessary
4257 + * (such as holding appropriate locks) to avoid racing
4258 + * with another list-mutation primitive, such as list_add_tail_rcu()
4259 + * or list_del_rcu(), running on this same list.
4260 + * However, it is perfectly legal to run concurrently with
4261 + * the _rcu list-traversal primitives, such as
4262 + * list_for_each_entry_rcu().
4264 +static inline void list_add_tail_rcu(struct list_head *new,
4265 + struct list_head *head)
4267 + __list_add_rcu(new, head->prev, head);
4271 + * Delete a list entry by making the prev/next entries
4272 + * point to each other.
4274 + * This is only for internal list manipulation where we know
4275 + * the prev/next entries already!
4277 +static inline void __list_del(struct list_head * prev, struct list_head * next)
4279 + next->prev = prev;
4280 + prev->next = next;
4284 + * list_del - deletes entry from list.
4285 + * @entry: the element to delete from the list.
4286 + * Note: list_empty on entry does not return true after this, the entry is
4287 + * in an undefined state.
4289 +static inline void list_del(struct list_head *entry)
4291 + __list_del(entry->prev, entry->next);
4292 + entry->next = LIST_POISON1;
4293 + entry->prev = LIST_POISON2;
4297 + * list_del_rcu - deletes entry from list without re-initialization
4298 + * @entry: the element to delete from the list.
4300 + * Note: list_empty on entry does not return true after this,
4301 + * the entry is in an undefined state. It is useful for RCU based
4302 + * lockfree traversal.
4304 + * In particular, it means that we can not poison the forward
4305 + * pointers that may still be used for walking the list.
4307 + * The caller must take whatever precautions are necessary
4308 + * (such as holding appropriate locks) to avoid racing
4309 + * with another list-mutation primitive, such as list_del_rcu()
4310 + * or list_add_rcu(), running on this same list.
4311 + * However, it is perfectly legal to run concurrently with
4312 + * the _rcu list-traversal primitives, such as
4313 + * list_for_each_entry_rcu().
4315 + * Note that the caller is not permitted to immediately free
4316 + * the newly deleted entry. Instead, either synchronize_kernel()
4317 + * or call_rcu() must be used to defer freeing until an RCU
4318 + * grace period has elapsed.
4320 +static inline void list_del_rcu(struct list_head *entry)
4322 + __list_del(entry->prev, entry->next);
4323 + entry->prev = LIST_POISON2;
4327 + * list_del_init - deletes entry from list and reinitialize it.
4328 + * @entry: the element to delete from the list.
4330 +static inline void list_del_init(struct list_head *entry)
4332 + __list_del(entry->prev, entry->next);
4333 + INIT_LIST_HEAD(entry);
4337 + * list_move - delete from one list and add as another's head
4338 + * @list: the entry to move
4339 + * @head: the head that will precede our entry
4341 +static inline void list_move(struct list_head *list, struct list_head *head)
4343 + __list_del(list->prev, list->next);
4344 + list_add(list, head);
4348 + * list_move_tail - delete from one list and add as another's tail
4349 + * @list: the entry to move
4350 + * @head: the head that will follow our entry
4352 +static inline void list_move_tail(struct list_head *list,
4353 + struct list_head *head)
4355 + __list_del(list->prev, list->next);
4356 + list_add_tail(list, head);
4360 + * list_empty - tests whether a list is empty
4361 + * @head: the list to test.
4363 +static inline int list_empty(const struct list_head *head)
4365 + return head->next == head;
4369 + * list_empty_careful - tests whether a list is
4370 + * empty _and_ checks that no other CPU might be
4371 + * in the process of still modifying either member
4373 + * NOTE: using list_empty_careful() without synchronization
4374 + * can only be safe if the only activity that can happen
4375 + * to the list entry is list_del_init(). Eg. it cannot be used
4376 + * if another CPU could re-list_add() it.
4378 + * @head: the list to test.
4380 +static inline int list_empty_careful(const struct list_head *head)
4382 + struct list_head *next = head->next;
4383 + return (next == head) && (next == head->prev);
4386 +static inline void __list_splice(struct list_head *list,
4387 + struct list_head *head)
4389 + struct list_head *first = list->next;
4390 + struct list_head *last = list->prev;
4391 + struct list_head *at = head->next;
4393 + first->prev = head;
4394 + head->next = first;
4401 + * list_splice - join two lists
4402 + * @list: the new list to add.
4403 + * @head: the place to add it in the first list.
4405 +static inline void list_splice(struct list_head *list, struct list_head *head)
4407 + if (!list_empty(list))
4408 + __list_splice(list, head);
4412 + * list_splice_init - join two lists and reinitialise the emptied list.
4413 + * @list: the new list to add.
4414 + * @head: the place to add it in the first list.
4416 + * The list at @list is reinitialised
4418 +static inline void list_splice_init(struct list_head *list,
4419 + struct list_head *head)
4421 + if (!list_empty(list)) {
4422 + __list_splice(list, head);
4423 + INIT_LIST_HEAD(list);
4428 + * list_entry - get the struct for this entry
4429 + * @ptr: the &struct list_head pointer.
4430 + * @type: the type of the struct this is embedded in.
4431 + * @member: the name of the list_struct within the struct.
4433 +#define list_entry(ptr, type, member) \
4434 + container_of(ptr, type, member)
4437 + * list_for_each - iterate over a list
4438 + * @pos: the &struct list_head to use as a loop counter.
4439 + * @head: the head for your list.
4441 +#define list_for_each(pos, head) \
4442 + for (pos = (head)->next, prefetch(pos->next); pos != (head); \
4443 + pos = pos->next, prefetch(pos->next))
4446 + * __list_for_each - iterate over a list
4447 + * @pos: the &struct list_head to use as a loop counter.
4448 + * @head: the head for your list.
4450 + * This variant differs from list_for_each() in that it's the
4451 + * simplest possible list iteration code, no prefetching is done.
4452 + * Use this for code that knows the list to be very short (empty
4453 + * or 1 entry) most of the time.
4455 +#define __list_for_each(pos, head) \
4456 + for (pos = (head)->next; pos != (head); pos = pos->next)
4459 + * list_for_each_prev - iterate over a list backwards
4460 + * @pos: the &struct list_head to use as a loop counter.
4461 + * @head: the head for your list.
4463 +#define list_for_each_prev(pos, head) \
4464 + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
4465 + pos = pos->prev, prefetch(pos->prev))
4468 + * list_for_each_safe - iterate over a list safe against removal of list entry
4469 + * @pos: the &struct list_head to use as a loop counter.
4470 + * @n: another &struct list_head to use as temporary storage
4471 + * @head: the head for your list.
4473 +#define list_for_each_safe(pos, n, head) \
4474 + for (pos = (head)->next, n = pos->next; pos != (head); \
4475 + pos = n, n = pos->next)
4478 + * list_for_each_entry - iterate over list of given type
4479 + * @pos: the type * to use as a loop counter.
4480 + * @head: the head for your list.
4481 + * @member: the name of the list_struct within the struct.
4483 +#define list_for_each_entry(pos, head, member) \
4484 + for (pos = list_entry((head)->next, typeof(*pos), member), \
4485 + prefetch(pos->member.next); \
4486 + &pos->member != (head); \
4487 + pos = list_entry(pos->member.next, typeof(*pos), member), \
4488 + prefetch(pos->member.next))
4491 + * list_for_each_entry_reverse - iterate backwards over list of given type.
4492 + * @pos: the type * to use as a loop counter.
4493 + * @head: the head for your list.
4494 + * @member: the name of the list_struct within the struct.
4496 +#define list_for_each_entry_reverse(pos, head, member) \
4497 + for (pos = list_entry((head)->prev, typeof(*pos), member), \
4498 + prefetch(pos->member.prev); \
4499 + &pos->member != (head); \
4500 + pos = list_entry(pos->member.prev, typeof(*pos), member), \
4501 + prefetch(pos->member.prev))
4504 + * list_prepare_entry - prepare a pos entry for use as a start point in
4505 + * list_for_each_entry_continue
4506 + * @pos: the type * to use as a start point
4507 + * @head: the head of the list
4508 + * @member: the name of the list_struct within the struct.
4510 +#define list_prepare_entry(pos, head, member) \
4511 + ((pos) ? : list_entry(head, typeof(*pos), member))
4514 + * list_for_each_entry_continue - iterate over list of given type
4515 + * continuing after existing point
4516 + * @pos: the type * to use as a loop counter.
4517 + * @head: the head for your list.
4518 + * @member: the name of the list_struct within the struct.
4520 +#define list_for_each_entry_continue(pos, head, member) \
4521 + for (pos = list_entry(pos->member.next, typeof(*pos), member), \
4522 + prefetch(pos->member.next); \
4523 + &pos->member != (head); \
4524 + pos = list_entry(pos->member.next, typeof(*pos), member), \
4525 + prefetch(pos->member.next))
4528 + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
4529 + * @pos: the type * to use as a loop counter.
4530 + * @n: another type * to use as temporary storage
4531 + * @head: the head for your list.
4532 + * @member: the name of the list_struct within the struct.
4534 +#define list_for_each_entry_safe(pos, n, head, member) \
4535 + for (pos = list_entry((head)->next, typeof(*pos), member), \
4536 + n = list_entry(pos->member.next, typeof(*pos), member); \
4537 + &pos->member != (head); \
4538 + pos = n, n = list_entry(n->member.next, typeof(*n), member))
4541 + * list_for_each_rcu - iterate over an rcu-protected list
4542 + * @pos: the &struct list_head to use as a loop counter.
4543 + * @head: the head for your list.
4545 + * This list-traversal primitive may safely run concurrently with
4546 + * the _rcu list-mutation primitives such as list_add_rcu()
4547 + * as long as the traversal is guarded by rcu_read_lock().
4549 +#define list_for_each_rcu(pos, head) \
4550 + for (pos = (head)->next, prefetch(pos->next); pos != (head); \
4551 + pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
4553 +#define __list_for_each_rcu(pos, head) \
4554 + for (pos = (head)->next; pos != (head); \
4555 + pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
4558 + * list_for_each_safe_rcu - iterate over an rcu-protected list safe
4559 + * against removal of list entry
4560 + * @pos: the &struct list_head to use as a loop counter.
4561 + * @n: another &struct list_head to use as temporary storage
4562 + * @head: the head for your list.
4564 + * This list-traversal primitive may safely run concurrently with
4565 + * the _rcu list-mutation primitives such as list_add_rcu()
4566 + * as long as the traversal is guarded by rcu_read_lock().
4568 +#define list_for_each_safe_rcu(pos, n, head) \
4569 + for (pos = (head)->next, n = pos->next; pos != (head); \
4570 + pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
4573 + * list_for_each_entry_rcu - iterate over rcu list of given type
4574 + * @pos: the type * to use as a loop counter.
4575 + * @head: the head for your list.
4576 + * @member: the name of the list_struct within the struct.
4578 + * This list-traversal primitive may safely run concurrently with
4579 + * the _rcu list-mutation primitives such as list_add_rcu()
4580 + * as long as the traversal is guarded by rcu_read_lock().
4582 +#define list_for_each_entry_rcu(pos, head, member) \
4583 + for (pos = list_entry((head)->next, typeof(*pos), member), \
4584 + prefetch(pos->member.next); \
4585 + &pos->member != (head); \
4586 + pos = list_entry(pos->member.next, typeof(*pos), member), \
4587 + ({ smp_read_barrier_depends(); 0;}), \
4588 + prefetch(pos->member.next))
4592 + * list_for_each_continue_rcu - iterate over an rcu-protected list
4593 + * continuing after existing point.
4594 + * @pos: the &struct list_head to use as a loop counter.
4595 + * @head: the head for your list.
4597 + * This list-traversal primitive may safely run concurrently with
4598 + * the _rcu list-mutation primitives such as list_add_rcu()
4599 + * as long as the traversal is guarded by rcu_read_lock().
4601 +#define list_for_each_continue_rcu(pos, head) \
4602 + for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
4603 + (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
4606 + * Double linked lists with a single pointer list head.
4607 + * Mostly useful for hash tables where the two pointer list head is
4609 + * You lose the ability to access the tail in O(1).
4612 +struct hlist_head {
4613 + struct hlist_node *first;
4616 +struct hlist_node {
4617 + struct hlist_node *next, **pprev;
4620 +#define HLIST_HEAD_INIT { .first = NULL }
4621 +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
4622 +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
4623 +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
4625 +static inline int hlist_unhashed(const struct hlist_node *h)
4630 +static inline int hlist_empty(const struct hlist_head *h)
4635 +static inline void __hlist_del(struct hlist_node *n)
4637 + struct hlist_node *next = n->next;
4638 + struct hlist_node **pprev = n->pprev;
4641 + next->pprev = pprev;
4644 +static inline void hlist_del(struct hlist_node *n)
4647 + n->next = LIST_POISON1;
4648 + n->pprev = LIST_POISON2;
4652 + * hlist_del_rcu - deletes entry from hash list without re-initialization
4653 + * @n: the element to delete from the hash list.
4655 + * Note: list_unhashed() on entry does not return true after this,
4656 + * the entry is in an undefined state. It is useful for RCU based
4657 + * lockfree traversal.
4659 + * In particular, it means that we can not poison the forward
4660 + * pointers that may still be used for walking the hash list.
4662 + * The caller must take whatever precautions are necessary
4663 + * (such as holding appropriate locks) to avoid racing
4664 + * with another list-mutation primitive, such as hlist_add_head_rcu()
4665 + * or hlist_del_rcu(), running on this same list.
4666 + * However, it is perfectly legal to run concurrently with
4667 + * the _rcu list-traversal primitives, such as
4668 + * hlist_for_each_entry().
4670 +static inline void hlist_del_rcu(struct hlist_node *n)
4673 + n->pprev = LIST_POISON2;
4676 +static inline void hlist_del_init(struct hlist_node *n)
4680 + INIT_HLIST_NODE(n);
4684 +#define hlist_del_rcu_init hlist_del_init
4686 +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
4688 + struct hlist_node *first = h->first;
4691 + first->pprev = &n->next;
4693 + n->pprev = &h->first;
4698 + * hlist_add_head_rcu - adds the specified element to the specified hlist,
4699 + * while permitting racing traversals.
4700 + * @n: the element to add to the hash list.
4701 + * @h: the list to add to.
4703 + * The caller must take whatever precautions are necessary
4704 + * (such as holding appropriate locks) to avoid racing
4705 + * with another list-mutation primitive, such as hlist_add_head_rcu()
4706 + * or hlist_del_rcu(), running on this same list.
4707 + * However, it is perfectly legal to run concurrently with
4708 + * the _rcu list-traversal primitives, such as
4709 + * hlist_for_each_entry(), but only if smp_read_barrier_depends()
4710 + * is used to prevent memory-consistency problems on Alpha CPUs.
4711 + * Regardless of the type of CPU, the list-traversal primitive
4712 + * must be guarded by rcu_read_lock().
4714 + * OK, so why don't we have an hlist_for_each_entry_rcu()???
4716 +static inline void hlist_add_head_rcu(struct hlist_node *n,
4717 + struct hlist_head *h)
4719 + struct hlist_node *first = h->first;
4721 + n->pprev = &h->first;
4724 + first->pprev = &n->next;
4728 +/* next must be != NULL */
4729 +static inline void hlist_add_before(struct hlist_node *n,
4730 + struct hlist_node *next)
4732 + n->pprev = next->pprev;
4734 + next->pprev = &n->next;
4738 +static inline void hlist_add_after(struct hlist_node *n,
4739 + struct hlist_node *next)
4741 + next->next = n->next;
4743 + next->pprev = &n->next;
4746 + next->next->pprev = &next->next;
4749 +#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
4751 +#define hlist_for_each(pos, head) \
4752 + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
4755 +#define hlist_for_each_safe(pos, n, head) \
4756 + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
4760 + * hlist_for_each_entry - iterate over list of given type
4761 + * @tpos: the type * to use as a loop counter.
4762 + * @pos: the &struct hlist_node to use as a loop counter.
4763 + * @head: the head for your list.
4764 + * @member: the name of the hlist_node within the struct.
4766 +#define hlist_for_each_entry(tpos, pos, head, member) \
4767 + for (pos = (head)->first; \
4768 + pos && ({ prefetch(pos->next); 1;}) && \
4769 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
4773 + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
4774 + * @tpos: the type * to use as a loop counter.
4775 + * @pos: the &struct hlist_node to use as a loop counter.
4776 + * @member: the name of the hlist_node within the struct.
4778 +#define hlist_for_each_entry_continue(tpos, pos, member) \
4779 + for (pos = (pos)->next; \
4780 + pos && ({ prefetch(pos->next); 1;}) && \
4781 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
4785 + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
4786 + * @tpos: the type * to use as a loop counter.
4787 + * @pos: the &struct hlist_node to use as a loop counter.
4788 + * @member: the name of the hlist_node within the struct.
4790 +#define hlist_for_each_entry_from(tpos, pos, member) \
4791 + for (; pos && ({ prefetch(pos->next); 1;}) && \
4792 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
4796 + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
4797 + * @tpos: the type * to use as a loop counter.
4798 + * @pos: the &struct hlist_node to use as a loop counter.
4799 + * @n: another &struct hlist_node to use as temporary storage
4800 + * @head: the head for your list.
4801 + * @member: the name of the hlist_node within the struct.
4803 +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
4804 + for (pos = (head)->first; \
4805 + pos && ({ n = pos->next; 1; }) && \
4806 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
4810 + * hlist_for_each_entry_rcu - iterate over rcu list of given type
4811 + * @pos: the type * to use as a loop counter.
4812 + * @pos: the &struct hlist_node to use as a loop counter.
4813 + * @head: the head for your list.
4814 + * @member: the name of the hlist_node within the struct.
4816 + * This list-traversal primitive may safely run concurrently with
4817 + * the _rcu list-mutation primitives such as hlist_add_rcu()
4818 + * as long as the traversal is guarded by rcu_read_lock().
4820 +#define hlist_for_each_entry_rcu(tpos, pos, head, member) \
4821 + for (pos = (head)->first; \
4822 + pos && ({ prefetch(pos->next); 1;}) && \
4823 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
4824 + pos = pos->next, ({ smp_read_barrier_depends(); 0; }) )