]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blame - src/patches/ipac-ng-1.31-iptables-1.3.1.patch
Wir kehren zurueck zu Kudzu, da hwinfo noch mehr Aerger macht.
[people/teissler/ipfire-2.x.git] / src / patches / ipac-ng-1.31-iptables-1.3.1.patch
CommitLineData
c2b15814
MT
1diff -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
4@@ -62,10 +62,6 @@
5 #define FALSE 0
6 #endif
7
8-#ifndef IPT_LIB_DIR
9-#define IPT_LIB_DIR "/lib/iptables"
10-#endif
11-
12 #define FMT_NUMERIC 0x0001
13 #define FMT_NOCOUNTS 0x0002
14 #define FMT_KILOMEGAGIGA 0x0004
15@@ -91,7 +87,6 @@
16 static struct option *opts = original_opts;
17 static unsigned int global_option_offset = 0;
18
19-extern char *authhost;
20
21 /* - T.Mohan 5/7/2001
22 * interface structure to pass to append rule
23@@ -106,6 +101,14 @@
24 typedef struct iface_struct s_iface;
25
26
27+struct iptables_rule_match
28+{
29+ struct iptables_rule_match *next;
30+
31+ struct iptables_match *match;
32+};
33+
34+
35 /* Include file for additions: new matches and targets. */
36 struct iptables_match
37 {
38@@ -113,6 +116,9 @@
39
40 ipt_chainlabel name;
41
42+ /* Revision of match (0 by default). */
43+ u_int8_t revision;
44+
45 const char *version;
46
47 /* Size of match data. */
48@@ -152,7 +158,6 @@
49 unsigned int option_offset;
50 struct ipt_entry_match *m;
51 unsigned int mflags;
52- unsigned int used;
53 };
54
55 struct iptables_target
56@@ -161,6 +166,9 @@
57
58 ipt_chainlabel name;
59
60+ /* Revision of target (0 by default). */
61+ u_int8_t revision;
62+
63 const char *version;
64
65 /* Size of target data. */
66@@ -202,6 +210,7 @@
67 unsigned int used;
68 };
69
70+
71 enum ipt_tryload {
72 DONT_LOAD,
73 TRY_LOAD,
74@@ -246,6 +255,9 @@
75 * compiler warning.
76 */
77
78+char *lib_dir = "/lib/iptables";
79+
80+
81 void
82 exit_error(enum exittype status, char *msg, ...)
83 {
84@@ -367,7 +379,7 @@
85 * iptables-1.2.2 file:iptables.c
86 */
87
88-void
89+static void
90 parse_interface(const char *arg, char *vianame, unsigned char *mask)
91 {
92 int vialen = strlen(arg);
93@@ -382,23 +394,25 @@
94 " (%i)", arg, IFNAMSIZ-1);
95
96 strcpy(vianame, arg);
97- if (vialen == 0)
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 */
104 } else {
105 /* Include nul-terminator in match */
106 memset(mask, 0xFF, vialen + 1);
107 memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
108- }
109 for (i = 0; vianame[i]; i++) {
110 if (!isalnum(vianame[i])
111 && 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",
118+ vianame);
119+ break;
120+ }
121 }
122 }
123 }
124@@ -429,20 +443,27 @@
125 }
126
127 int
128-check_inverse(const char option[], int *invert)
129+check_inverse(const char option[], int *invert, int *optind, int argc)
130 {
131 if (option && strcmp(option, "!") == 0) {
132 if (*invert)
133 exit_error(PARAMETER_PROBLEM,
134 "Multiple `!' flags not allowed");
135-
136 *invert = TRUE;
137+ if (optind) {
138+ *optind = *optind+1;
139+ if (argc && *optind > argc)
140+ exit_error(PARAMETER_PROBLEM,
141+ "no argument following `!'");
142+ }
143+
144 return TRUE;
145 }
146 return FALSE;
147 }
148
149 // ---------------------------------------------------------------------
150+/* code copied from iptables 1.3.1 */
151 // ---------------------------------------------------------------------
152
153 static char *
154@@ -509,7 +530,7 @@
155 return addr_to_dotted(addr);
156 }
157
158-static char *
159+char *
160 mask_to_dotted(const struct in_addr *mask)
161 {
162 int i;
163@@ -535,22 +556,19 @@
164 return buf;
165 }
166
167+
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)
173 {
174 unsigned int size;
175- struct iptables_match *m;
176+ struct iptables_rule_match *matchp;
177 struct ipt_entry *e;
178
179 size = sizeof(struct ipt_entry);
180- for (m = matches; m; m = m->next) {
181- if (!m->used)
182- continue;
183-
184- size += m->m->u.match_size;
185- }
186+ for (matchp = matches; matchp; matchp = matchp->next)
187+ size += matchp->match->m->u.match_size;
188
189 e = xmalloc(size + target->u.target_size);
190 *e = *fw;
191@@ -558,12 +576,9 @@
192 e->next_offset = size + target->u.target_size;
193
194 size = 0;
195- for (m = matches; m; m = m->next) {
196- if (!m->used)
197- continue;
198-
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;
204 }
205 memcpy(e->elems + size, target, target->u.target_size);
206
207@@ -575,15 +590,17 @@
208 int procfile;
209 char *ret;
210
211+#define PROCFILE_BUFSIZ 1024
212 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
213 if (procfile < 0)
214 return NULL;
215
216- ret = malloc(1024);
217+ ret = (char *) malloc(PROCFILE_BUFSIZ);
218 if (ret) {
219- switch (read(procfile, ret, 1024)) {
220+ memset(ret, 0, PROCFILE_BUFSIZ);
221+ switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
222 case -1: goto fail;
223- case 1024: goto fail; /* Partial read. Wierd */
224+ case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */
225 }
226 if (ret[strlen(ret)-1]=='\n')
227 ret[strlen(ret)-1]=0;
228@@ -618,22 +635,22 @@
229 }
230
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")
234 + strlen(name)];
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);
241 if (!ptr) {
242- fprintf(stderr, "Couldn't load target `%s'\n",
243+ exit_error(PARAMETER_PROBLEM,
244+ "Couldn't load target `%s'\n",
245 name);
246- exit(1);
247 }
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",
252 name, dlerror());
253- exit(1);
254 }
255 }
256
257@@ -647,8 +664,9 @@
258 {
259 char *buf = NULL;
260 char *argv[3];
261+ int status;
262
263-// If they don't explicitly set it, read out of kernel
264+ /* If they don't explicitly set it, read out of kernel */
265 if (!modprobe) {
266 buf = get_modprobe();
267 if (!buf)
268@@ -664,16 +682,18 @@
269 execv(argv[0], argv);
270
271 // not usually reached
272- exit(0);
273+ exit(1);
274 case -1:
275 return -1;
276
277 default: // parent
278- wait(NULL);
279+ wait(&status);
280 }
281
282 free(buf);
283+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
284 return 0;
285+ return -1;
286 }
287
288 void
289@@ -687,7 +707,7 @@
290
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);
295 exit(1);
296 }
297
298@@ -698,20 +718,17 @@
299 me->tflags = 0;
300 }
301
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)
305 {
306 /* Establish mask for comparison */
307 unsigned int size;
308- struct iptables_match *m;
309+ struct iptables_rule_match *matchp;
310 unsigned char *mask, *mptr;
311
312 size = sizeof(struct ipt_entry);
313- for (m = iptables_matches; m; m = m->next) {
314- if (!m->used)
315- continue;
316-
317- size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
318- }
319+ for (matchp = matches; matchp; matchp = matchp->next)
320+ size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size;
321
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);
327
328- for (m = iptables_matches; m; m = m->next) {
329- if (!m->used)
330- continue;
331-
332+ for (matchp = matches; matchp; matchp = matchp->next) {
333 memset(mptr, 0xFF,
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;
339 }
340
341 memset(mptr, 0xFF,
342@@ -738,7 +752,7 @@
343 }
344
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)
348 {
349 struct iptables_match *ptr;
350
351@@ -748,28 +762,37 @@
352 }
353
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")
357 + strlen(name)];
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);
365
366 if (!ptr) {
367- fprintf(stderr, "Couldn't load match `%s'\n",
368+ exit_error(PARAMETER_PROBLEM,
369+ "Couldn't load match `%s'\n",
370 name);
371- exit(1);
372 }
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",
377 name, dlerror());
378- exit(1);
379 }
380 }
381
382- if (ptr)
383- ptr->used = 1;
384+ if (ptr && matches) {
385+ struct iptables_rule_match **i;
386+ struct iptables_rule_match *newentry;
387+
388+ newentry = xmalloc(sizeof(struct iptables_rule_match));
389+
390+ for (i = matches; *i; i = &(*i)->next);
391+ newentry->match = ptr;
392+ newentry->next = NULL;
393+ *i = newentry;
394+ }
395
396 return ptr;
397 }
398@@ -779,7 +802,7 @@
399 {
400 struct iptables_match **i;
401
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);
406 exit(1);
407@@ -787,7 +810,7 @@
408
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);
413 exit(1);
414 }
415
416@@ -801,16 +824,21 @@
417 }
418
419
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)
424 {
425- int proto;
426+ unsigned int proto;
427
428- proto = string_to_number(pname, 0, 255);
429- if (proto != -1)
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);
433
434- return find_match(pname, tryload);
435+ if (protoname)
436+ return find_match(protoname, tryload, matches);
437+ } else
438+ return find_match(pname, tryload, matches);
439+
440+ return NULL;
441 }
442
443 static void
444@@ -823,15 +851,19 @@
445 number = (number + 500) / 1000;
446 if (number > 9999) {
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);
452 }
453- else printf(FMT("%4lluM ","%lluM "), number);
454+ else printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
455+ }
456+ else printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
457 } else
458- printf(FMT("%4lluK ","%lluK "), number);
459+ printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
460 } else
461- printf(FMT("%5llu ","%llu "), number);
462+ printf(FMT("%5llu ","%llu "), (unsigned long long)number);
463 } else
464- printf(FMT("%8llu ","%llu "), number);
465+ printf(FMT("%8llu ","%llu "), (unsigned long long)number);
466 }
467
468 static int
469@@ -839,7 +871,7 @@
470 const struct ipt_ip *ip,
471 int numeric)
472 {
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);
475
476 if (match) {
477 if (match->print)
478@@ -867,9 +899,6 @@
479 u_int8_t flags;
480 char buf[BUFSIZ];
481
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);
487 else
488@@ -917,10 +946,6 @@
489
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
493- wildcard. */
494- if (fw->ip.iniface_mask[strlen(fw->ip.iniface)] == 0)
495- strcat(iface, "+");
496 }
497 else if (format & FMT_NUMERIC) strcat(iface, "*");
498 else strcat(iface, "any");
499@@ -934,10 +959,6 @@
500
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
504- wildcard. */
505- if (fw->ip.outiface_mask[strlen(fw->ip.outiface)] == 0)
506- strcat(iface, "+");
507 }
508 else if (format & FMT_NUMERIC) strcat(iface, "*");
509 else strcat(iface, "any");
510@@ -979,7 +1000,7 @@
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)));
516
517 if (!(format & FMT_NONEWLINE))
518 fputc('\n', stdout);
519@@ -996,6 +1017,15 @@
520 }
521
522
523+static void set_revision(char *name, u_int8_t revision)
524+{
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;
529+}
530+
531+
532 // ---------------------------------------------------------------------
533
534
535@@ -1129,8 +1159,7 @@
536 chain->pkts++;
537 continue;
538 }
539-
540- counters = iptc_read_counter(chain->name, chain->pkts, &handle);
541+ counters = iptc_read_counter(chain->name, chain->pkts, &handle); // ???? why chain->pkts
542 if (counters) {
543 iptc_zero_counter(chain->name, chain->pkts, &handle);
544 chain->pkts++;
545@@ -1192,7 +1221,7 @@
546 *
547 */
548 static int
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)
551 {
552 struct ipt_entry fw;
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;
558+
559+ struct iptables_rule_match *matchp;
560+
561 size_t size;
562 int inverse;
563 int c,argc;
564 int invert = 0;
565+ int proto_used = 0;
566
567 bzero(&fw, sizeof(fw));
568
569@@ -1233,7 +1266,6 @@
570
571 for (m = iptables_matches; m; m = m->next) {
572 m->mflags = 0;
573- m->used = 0;
574 }
575
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);
584
585 if(check_inverse_type(d->protocol))
586@@ -1290,7 +1324,7 @@
587 }
588
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) {
597 switch (c) {
598 case 'm':
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 @@
605 exit(1);
606
607 default:
608- for (m = iptables_matches; m; m = m->next) {
609- if (!m->used)
610- continue;
611- if (m->parse(c - m->option_offset,
612+
613+ /* FIXME: This scheme doesn't allow two of the same
614+ matches --RR */
615+ if (!target
616+ || !(target->parse(c - target->option_offset,
617+ d->extension, invert,
618+ &target->tflags,
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,
623- &m->mflags,
624- &fw, &fw.nfcache, &m->m))
625+ &matchp->match->mflags,
626+ &fw,
627+ &fw.nfcache,
628+ &matchp->match->m))
629 break;
630 }
631- break;
632+
633+ if (m == NULL
634+ && d->protocol
635+ && (!find_proto(d->protocol, DONT_LOAD,
636+ 0, NULL)
637+ || (find_proto(d->protocol, DONT_LOAD,
638+ 0, NULL)
639+ && (proto_used == 0))
640+ )
641+ && (m = find_proto(d->protocol, TRY_LOAD,
642+ 0, matches))) {
643+ /* Try loading protocol */
644+ size_t size;
645+
646+ proto_used = 1;
647+
648+ size = IPT_ALIGN(sizeof(struct ipt_entry_match))
649+ + m->size;
650+
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,
655+ m->revision);
656+ if (m->init != NULL)
657+ m->init(m->m, &fw.nfcache);
658+
659+ opts = merge_options(opts,
660+ m->extra_opts, &m->option_offset);
661+
662+ optind--;
663+ continue;
664+ }
665+
666+ m = matchp ? matchp->match : NULL;
667+ if (!m)
668+ exit_error(PARAMETER_PROBLEM,
669+ "Unknown arg `%s'",
670+ d->extension);
671 }
672 }
673 }
674- for (m = iptables_matches; m; m = m->next) {
675- if (!m->used)
676- continue;
677- m->final_check(m->mflags);
678 }
679
680+ for (matchp = *matches; matchp; matchp = matchp->next)
681+ matchp->match->final_check(matchp->match->mflags);
682+
683+ if (target)
684 target->final_check(target->tflags);
685- *e = generate_entry(&fw, iptables_matches, target->t);
686+
687+ *e = generate_entry(&fw, *matches, target->t);
688+ free(target->t);
689+
690
691 if (!handle) if (!(handle = iptc_init("filter")))
692 exit_error(PARAMETER_PROBLEM,
693 "iptables: %s\n", iptc_strerror(errno));
694-
695 return 0;
696 }
697
698@@ -1399,9 +1481,11 @@
699 insert_rule(raw_rule_type *d, int rule_num)
700 {
701 struct ipt_entry *e = NULL;
702+ struct iptables_rule_match *matches = NULL;
703+
704 int ret=1;
705
706- if (prepare_entry(d, &e)!=0)
707+ if (prepare_entry(d, &e, &matches)!=0)
708 return (1);
709 if (verbose>1) {
710 printf("Inserting rule\n");
711@@ -1412,28 +1496,6 @@
712 return ret;
713 }
714
715-/*
716- * Try to atomically replace rule in kernel return 0 in case all right, 1 otherwice
717- */
718-static int
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)
722-{
723- struct ipt_entry *e = NULL;
724- int ret=1;
725-
726- if (prepare_entry(d, &e)!=0)
727- return (1);
728-
729- if (verbose>1) {
730- printf("Replacing rule %d in '%s'\n", rule_num, d->dest);
731- print_firewall_line(e, handle);
732- }
733- ret &= iptc_replace_entry(d->dest, e, rule_num, &handle);
734- free(e);
735- return ret;
736-}
737
738 /*
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)
742 {
743 struct ipt_entry *e = NULL;
744+ struct iptables_rule_match *matches = NULL;
745
746- if (prepare_entry(d, &e)!=0)
747+ if (prepare_entry(d, &e, &matches)!=0)
748 return (1);
749
750 if (verbose>1) {
751@@ -1472,9 +1535,11 @@
752 {
753 struct ipt_entry *e = NULL;
754 unsigned char *mask = NULL;
755+ struct iptables_rule_match *matches = NULL;
756+
757 int ret=1;
758
759- if (prepare_entry(d, &e)!=0)
760+ if (prepare_entry(d, &e, &matches)!=0)
761 return (1);
762
763 if (verbose>1) {
764@@ -1482,26 +1547,12 @@
765 print_firewall_line(e, handle);
766 }
767
768- mask = make_delete_mask(e);
769+ mask = make_delete_mask(e, matches);
770 ret &= iptc_delete_entry(d->dest, e, mask, &handle);
771 free(e);
772 return ret;
773 }
774
775-static int
776-delete_num_rule (char *chain, int num)
777-{
778- struct ipt_entry *e = NULL;
779- unsigned char *mask = NULL;
780- int ret = 1;
781-
782- mask = make_delete_mask(e);
783- ret &= iptc_delete_num_entry(chain, num, &handle);
784- free(e);
785- return ret;
786-}
787-
788-
789
790 /** Setup chains if they doesn't exist
791 *
792@@ -1588,11 +1639,9 @@
793 if (!handle)
794 handle = iptc_init("filter");
795
796- if (!handle) {
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");
802- }
803
804 if (!handle) {
805 fprintf(stderr, "ipac-ng: can't initialize iptables table `filter'\n"
806@@ -1617,7 +1666,6 @@
807 setup_rules(void)
808 {
809 raw_rule_type *d, *d1;
810- char targ[MAX_RULE_NAME_LENGTH+2];
811 char chain[MAX_RULE_NAME_LENGTH+2];
812 FILE *frunfile;
813
814diff -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
817@@ -16,6 +16,7 @@
818 #include <errno.h>
819 #include <stdlib.h>
820 #include <stdio.h>
821+#include <unistd.h>
822
823 #ifdef DEBUG_CONNTRACK
824 #define inline
825@@ -90,6 +91,7 @@
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
832
833@@ -121,121 +123,49 @@
834
835 #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
836
837-int
838-dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle)
839-{
840- size_t i;
841- STRUCT_ENTRY_TARGET *t;
842-
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 ");
874- printf("\n");
875-
876- IPT_MATCH_ITERATE(e, print_match);
877-
878- t = GET_TARGET(e);
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;
882- if (pos < 0)
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"
888- : "UNKNOWN");
889- else
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);
893-
894- printf("\n");
895- return 0;
896-}
897
898-static int
899+static unsigned char *
900 is_same(const STRUCT_ENTRY *a, const STRUCT_ENTRY *b, unsigned char *matchmask)
901 {
902 unsigned int i;
903- STRUCT_ENTRY_TARGET *ta, *tb;
904 unsigned char *mptr;
905
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)
915- return 0;
916+ return NULL;
917
918 for (i = 0; i < IFNAMSIZ; i++) {
919 if (a->ip.iniface_mask[i] != b->ip.iniface_mask[i])
920- return 0;
921+ return NULL;
922 if ((a->ip.iniface[i] & a->ip.iniface_mask[i])
923 != (b->ip.iniface[i] & b->ip.iniface_mask[i]))
924- return 0;
925+ return NULL;
926 if (a->ip.outiface_mask[i] != b->ip.outiface_mask[i])
927- return 0;
928+ return NULL;
929 if ((a->ip.outiface[i] & a->ip.outiface_mask[i])
930 != (b->ip.outiface[i] & b->ip.outiface_mask[i]))
931- return 0;
932+ return NULL;
933 }
934
935 if (a->nfcache != b->nfcache
936 || a->target_offset != b->target_offset
937 || a->next_offset != b->next_offset)
938- return 0;
939+ return NULL;
940
941 mptr = matchmask + sizeof(STRUCT_ENTRY);
942 if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems, &mptr))
943- return 0;
944+ return NULL;
945
946- ta = GET_TARGET((STRUCT_ENTRY *)a);
947- tb = GET_TARGET((STRUCT_ENTRY *)b);
948- if (ta->u.target_size != tb->u.target_size)
949- return 0;
950- if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
951- return 0;
952-
953- mptr += sizeof(*ta);
954- if (target_different(ta->data, tb->data,
955- ta->u.target_size - sizeof(*ta), mptr))
956- return 0;
957-
958- return 1;
959+ return mptr;
960 }
961
962+#if 0
963 /***************************** DEBUGGING ********************************/
964 static inline int
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);
972
973 if (t->verdict >= 0) {
974 STRUCT_ENTRY *te = get_entry(h, t->verdict);
975 int idx;
976
977- idx = entry2index(h, te);
978+ idx = iptcb_entry2index(h, te);
979 assert(strcmp(GET_TARGET(te)->u.user.name,
980 IPT_ERROR_TARGET)
981 != 0);
982 assert(te != e);
983
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)
989 == 0);
990@@ -335,7 +265,7 @@
991 return 0;
992 }
993
994-#ifndef NDEBUG
995+#ifdef IPTC_DEBUG
996 /* Do every conceivable sanity check on the handle */
997 static void
998 do_check(TC_HANDLE_T h, unsigned int line)
999@@ -364,35 +294,90 @@
1000
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)));
1014
1015 assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1016
1017 n = get_chain_end(h, 0);
1018+
1019 n += get_entry(h, n)->next_offset;
1020 assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n);
1021-
1022 n = get_chain_end(h, n);
1023+
1024 n += get_entry(h, n)->next_offset;
1025 assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1026-
1027 user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1028+
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];
1034+ }
1035+
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
1039+ * */
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)));
1049+
1050+ /* Hooks should be first five */
1051+ assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1052+
1053+ n = get_chain_end(h, 0);
1054+
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);
1059+ }
1060+
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);
1065+ }
1066+
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];
1070+
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];
1076+ }
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));
1081
1082- /* Hooks should be first two */
1083+ /* Hooks should be first three */
1084 assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1085
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);
1090
1091 user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1092+
1093 #ifdef NF_IP_DROPPING
1094 } else if (strcmp(h->info.name, "drop") == 0) {
1095 assert(h->info.valid_hooks == (1 << NF_IP_DROPPING));
1096@@ -425,8 +410,8 @@
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)));
1104
1105 assert(strcmp(t->target.u.user.name, STANDARD_TARGET)==0);
1106 assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1);
1107@@ -458,6 +443,8 @@
1108 /* Final entry must be error node */
1109 assert(strcmp(GET_TARGET(index2entry(h, h->new_number-1))
1110 ->u.user.name,
1111- IPT_ERROR_TARGET) == 0);
1112+ ERROR_TARGET) == 0);
1113 }
1114-#endif /*NDEBUG*/
1115+#endif /*IPTC_DEBUG*/
1116+
1117+#endif
1118diff -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
1121@@ -9,21 +9,43 @@
1122 */
1123
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>
1128+ *
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/)
1140+ */
1141+#include <sys/types.h>
1142+#include <sys/socket.h>
1143
1144-#ifndef IPT_LIB_DIR
1145-#define IPT_LIB_DIR "/lib/iptables"
1146+#include "linux_list.h"
1147+
1148+//#define IPTC_DEBUG2 1
1149+
1150+#ifdef IPTC_DEBUG2
1151+#include <fcntl.h>
1152+#define DEBUGP(x, args...) fprintf(stderr, "%s: " x, __FUNCTION__, ## args)
1153+#define DEBUGP_C(x, args...) fprintf(stderr, x, ## args)
1154+#else
1155+#define DEBUGP(x, args...)
1156+#define DEBUGP_C(x, args...)
1157 #endif
1158
1159-#ifndef __OPTIMIZE__
1160-STRUCT_ENTRY_TARGET *
1161-GET_TARGET(STRUCT_ENTRY *e)
1162-{
1163- return (void *)e + e->target_offset;
1164-}
1165+#ifndef IPT_LIB_DIR
1166+#define IPT_LIB_DIR "/usr/local/lib/iptables"
1167 #endif
1168
1169 static int sockfd = -1;
1170+static int sockfd_use = 0;
1171 static void *iptc_fn = NULL;
1172
1173 static const char *hooknames[]
1174@@ -37,6 +59,16 @@
1175 #endif
1176 };
1177
1178+/* Convenience structures */
1179+struct ipt_error_target
1180+{
1181+ STRUCT_ENTRY_TARGET t;
1182+ char error[TABLE_MAXNAMELEN];
1183+};
1184+
1185+struct chain_head;
1186+struct rule_head;
1187+
1188 struct counter_map
1189 {
1190 enum {
1191@@ -48,59 +80,95 @@
1192 unsigned int mappos;
1193 };
1194
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 */
1202+};
1203+
1204+struct rule_head
1205 {
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;
1211+
1212+ unsigned int index; /* index (needed for counter_map) */
1213+ unsigned int offset; /* offset in rule blob */
1214+
1215+ enum iptcc_rule_type type;
1216+ struct chain_head *jump; /* jump target, if IPTCC_R_JUMP */
1217+
1218+ unsigned int size; /* size of entry data */
1219+ STRUCT_ENTRY entry[0];
1220 };
1221
1222-struct chain_cache
1223+struct chain_head
1224 {
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 */
1234+
1235+ STRUCT_COUNTERS counters; /* per-chain counters */
1236+ struct counter_map counter_map;
1237+
1238+ unsigned int num_rules; /* number of rules in list */
1239+ struct list_head rules; /* list of rules */
1240+
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 */
1245 };
1246
1247 STRUCT_TC_HANDLE
1248 {
1249- /* Have changes been made? */
1250- int changed;
1251- /* Size in here reflects original state. */
1252- STRUCT_GETINFO info;
1253+ int changed; /* Have changes been made? */
1254+
1255+ struct list_head chains;
1256+
1257+ struct chain_head *chain_iterator_cur;
1258+ struct rule_head *rule_iterator_cur;
1259
1260- struct counter_map *counter_map;
1261- /* Array of hook names */
1262- const char **hooknames;
1263-
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;
1268-
1269- /* Chain iterator: current chain cache entry. */
1270- struct chain_cache *cache_chain_iteration;
1271-
1272- /* Rule iterator: terminal rule */
1273- STRUCT_ENTRY *cache_rule_end;
1274-
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;
1280 };
1281
1282+/* allocate a new chain head for the cache */
1283+static struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
1284+{
1285+ struct chain_head *c = malloc(sizeof(*c));
1286+ if (!c)
1287+ return NULL;
1288+ memset(c, 0, sizeof(*c));
1289+
1290+ strncpy(c->name, name, TABLE_MAXNAMELEN);
1291+ c->hooknum = hooknum;
1292+ INIT_LIST_HEAD(&c->rules);
1293+
1294+ return c;
1295+}
1296+
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)
1299+{
1300+ struct rule_head *r = malloc(sizeof(*r)+size);
1301+ if (!r)
1302+ return NULL;
1303+ memset(r, 0, sizeof(*r));
1304+
1305+ r->chain = c;
1306+ r->size = size;
1307+
1308+ return r;
1309+}
1310+
1311+/* notify us that the ruleset has been modified by the user */
1312 static void
1313 set_changed(TC_HANDLE_T h)
1314 {
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;
1321- }
1322 h->changed = 1;
1323 }
1324
1325@@ -111,8 +179,13 @@
1326 #define CHECK(h)
1327 #endif
1328
1329+
1330+/**********************************************************************
1331+ * iptc blob utility functions (iptcb_*)
1332+ **********************************************************************/
1333+
1334 static inline int
1335-get_number(const STRUCT_ENTRY *i,
1336+iptcb_get_number(const STRUCT_ENTRY *i,
1337 const STRUCT_ENTRY *seek,
1338 unsigned int *pos)
1339 {
1340@@ -122,22 +195,8 @@
1341 return 0;
1342 }
1343
1344-static unsigned int
1345-entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
1346-{
1347- unsigned int pos = 0;
1348-
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);
1353- abort();
1354- }
1355- return pos;
1356-}
1357-
1358 static inline int
1359-get_entry_n(STRUCT_ENTRY *i,
1360+iptcb_get_entry_n(STRUCT_ENTRY *i,
1361 unsigned int number,
1362 unsigned int *pos,
1363 STRUCT_ENTRY **pe)
1364@@ -150,51 +209,556 @@
1365 return 0;
1366 }
1367
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)
1372 {
1373- unsigned int pos = 0;
1374- STRUCT_ENTRY *ret = NULL;
1375+ return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset);
1376+}
1377
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)
1382+{
1383+ unsigned int pos = 0;
1384
1385- return ret;
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));
1390+ abort();
1391+ }
1392+ return pos;
1393 }
1394
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)
1398 {
1399- return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset);
1400+ return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset);
1401 }
1402
1403+
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)
1407 {
1408- return (char *)e - (char *)h->entries.entrytable;
1409+ return (void *)e - (void *)h->entries->entrytable;
1410 }
1411
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)
1416 {
1417- return entry2offset(h, index2entry(h, index));
1418+ return iptcb_entry2index(h, iptcb_offset2entry(h, offset));
1419 }
1420
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)
1426 {
1427- STRUCT_ENTRY *e;
1428+ unsigned int i;
1429
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",
1433- offset);
1434- abort();
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)
1438+ return i+1;
1439+ }
1440+ return 0;
1441+}
1442+
1443+
1444+/**********************************************************************
1445+ * iptc cache utility functions (iptcc_*)
1446+ **********************************************************************/
1447+
1448+/* Is the given chain builtin (1) or user-defined (0) */
1449+static unsigned int iptcc_is_builtin(struct chain_head *c)
1450+{
1451+ return (c->hooknum ? 1 : 0);
1452+}
1453+
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)
1457+{
1458+ struct rule_head *r;
1459+ unsigned int num = 0;
1460+
1461+ list_for_each_entry(r, &c->rules, list) {
1462+ num++;
1463+ if (num == rulenum)
1464+ return r;
1465+ }
1466+ return NULL;
1467+}
1468+
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)
1472+{
1473+ struct rule_head *r;
1474+ unsigned int num = 0;
1475+
1476+ list_for_each_entry_reverse(r, &c->rules, list) {
1477+ num++;
1478+ if (num == rulenum)
1479+ return r;
1480+ }
1481+ return NULL;
1482+}
1483+
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)
1487+{
1488+ struct list_head *pos;
1489+
1490+ if (list_empty(&handle->chains))
1491+ return NULL;
1492+
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)
1496+ return c;
1497+ }
1498+
1499+ return NULL;
1500+}
1501+/* Returns chain head if found, otherwise NULL. */
1502+static struct chain_head *
1503+iptcc_find_label(const char *name, TC_HANDLE_T handle)
1504+{
1505+ struct list_head *pos;
1506+
1507+ if (list_empty(&handle->chains))
1508+ return NULL;
1509+
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))
1513+ return c;
1514+ }
1515+
1516+ return NULL;
1517+}
1518+
1519+/* called when rule is to be removed from cache */
1520+static void iptcc_delete_rule(struct rule_head *r)
1521+{
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
1525+ && r->jump)
1526+ r->jump->references--;
1527+
1528+ list_del(&r->list);
1529+ free(r);
1530+}
1531+
1532+
1533+/**********************************************************************
1534+ * RULESET PARSER (blob -> cache)
1535+ **********************************************************************/
1536+
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)
1542+{
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;
1547+
1548+ /* save verdict */
1549+ h->chain_iterator_cur->verdict =
1550+ *(int *)GET_TARGET(pr->entry)->data;
1551+
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));
1558+
1559+ /* foot_offset points to verdict rule */
1560+ h->chain_iterator_cur->foot_index = num;
1561+ h->chain_iterator_cur->foot_offset = pr->offset;
1562+
1563+ /* delete rule from cache */
1564+ iptcc_delete_rule(pr);
1565+ h->chain_iterator_cur->num_rules--;
1566+
1567+ return 1;
1568+ }
1569+ return 0;
1570+}
1571+
1572+/* alphabetically insert a chain into the list */
1573+static inline void iptc_insert_chain(TC_HANDLE_T h, struct chain_head *c)
1574+{
1575+ struct chain_head *tmp;
1576+
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);
1582+ return;
1583+ }
1584+ }
1585+ }
1586+
1587+ /* survived till end of list: add at tail */
1588+ list_add_tail(&c->list, &h->chains);
1589+}
1590+
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)
1595+{
1596+ __iptcc_p_del_policy(h, *num);
1597+
1598+ c->head_offset = offset;
1599+ c->index = *num;
1600+
1601+ iptc_insert_chain(h, c);
1602+
1603+ h->chain_iterator_cur = c;
1604+}
1605+
1606+/* main parser function: add an entry from the blob to the cache */
1607+static int cache_add_entry(STRUCT_ENTRY *e,
1608+ TC_HANDLE_T h,
1609+ STRUCT_ENTRY **prev,
1610+ unsigned int *num)
1611+{
1612+ unsigned int builtin;
1613+ unsigned int offset = (char *)e - (char *)h->entries->entrytable;
1614+
1615+ DEBUGP("entering...");
1616+
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);
1621+
1622+ __iptcc_p_del_policy(h, *num);
1623+
1624+ h->chain_iterator_cur = NULL;
1625+ goto out_inc;
1626+ }
1627+
1628+ /* We know this is the start of a new chain if it's an ERROR
1629+ * target, or a hook entry point */
1630+
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);
1636+ if (!c) {
1637+ errno = -ENOMEM;
1638+ return -1;
1639+ }
1640+
1641+ __iptcc_p_add_chain(h, c, offset, num);
1642+
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],
1646+ builtin);
1647+ DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
1648+ *num, offset, c, &c->rules);
1649+ if (!c) {
1650+ errno = -ENOMEM;
1651+ return -1;
1652+ }
1653+
1654+ c->hooknum = builtin;
1655+
1656+ __iptcc_p_add_chain(h, c, offset, num);
1657+
1658+ /* FIXME: this is ugly. */
1659+ goto new_rule;
1660+ } else {
1661+ /* has to be normal rule */
1662+ struct rule_head *r;
1663+new_rule:
1664+
1665+ if (!(r = iptcc_alloc_rule(h->chain_iterator_cur,
1666+ e->next_offset))) {
1667+ errno = ENOMEM;
1668+ return -1;
1669+ }
1670+ DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
1671+
1672+ r->index = *num;
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;
1677+
1678+ /* handling of jumps, etc. */
1679+ if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) {
1680+ STRUCT_STANDARD_TARGET *t;
1681+
1682+ t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1683+ if (t->target.u.target_size
1684+ != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
1685+ errno = EINVAL;
1686+ return -1;
1687+ }
1688+
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;
1695+ } else {
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 */
1701+ }
1702+ } else {
1703+ DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name);
1704+ r->type = IPTCC_R_MODULE;
1705+ }
1706+
1707+ list_add_tail(&r->list, &h->chain_iterator_cur->rules);
1708+ h->chain_iterator_cur->num_rules++;
1709+ }
1710+out_inc:
1711+ (*num)++;
1712+ return 0;
1713+}
1714+
1715+
1716+/* parse an iptables blob into it's pieces */
1717+static int parse_table(TC_HANDLE_T h)
1718+{
1719+ STRUCT_ENTRY *prev;
1720+ unsigned int num = 0;
1721+ struct chain_head *c;
1722+
1723+ /* First pass: over ruleset blob */
1724+ ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
1725+ cache_add_entry, h, &prev, &num);
1726+
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;
1733+
1734+ if (r->type != IPTCC_R_JUMP)
1735+ continue;
1736+
1737+ t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
1738+ c = iptcc_find_chain_by_offset(h, t->verdict);
1739+ if (!c)
1740+ return -1;
1741+ r->jump = c;
1742+ c->references++;
1743+ }
1744+ }
1745+
1746+ /* FIXME: sort chains */
1747+
1748+ return 1;
1749+}
1750+
1751+
1752+/**********************************************************************
1753+ * RULESET COMPILATION (cache -> blob)
1754+ **********************************************************************/
1755+
1756+/* Convenience structures */
1757+struct iptcb_chain_start{
1758+ STRUCT_ENTRY e;
1759+ struct ipt_error_target name;
1760+};
1761+#define IPTCB_CHAIN_START_SIZE (sizeof(STRUCT_ENTRY) + \
1762+ ALIGN(sizeof(struct ipt_error_target)))
1763+
1764+struct iptcb_chain_foot {
1765+ STRUCT_ENTRY e;
1766+ STRUCT_STANDARD_TARGET target;
1767+};
1768+#define IPTCB_CHAIN_FOOT_SIZE (sizeof(STRUCT_ENTRY) + \
1769+ ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
1770+
1771+struct iptcb_chain_error {
1772+ STRUCT_ENTRY entry;
1773+ struct ipt_error_target target;
1774+};
1775+#define IPTCB_CHAIN_ERROR_SIZE (sizeof(STRUCT_ENTRY) + \
1776+ ALIGN(sizeof(struct ipt_error_target)))
1777+
1778+
1779+
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)
1782+{
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;
1797+ }
1798+
1799+ /* copy entry from cache to blob */
1800+ memcpy((char *)repl->entries+r->offset, r->entry, r->size);
1801+
1802+ return 1;
1803+}
1804+
1805+/* compile chain from cache into blob */
1806+static int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain_head *c)
1807+{
1808+ int ret;
1809+ struct rule_head *r;
1810+ struct iptcb_chain_start *head;
1811+ struct iptcb_chain_foot *foot;
1812+
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);
1823+ } else {
1824+ repl->hook_entry[c->hooknum-1] = c->head_offset;
1825+ repl->underflow[c->hooknum-1] = c->foot_offset;
1826+ }
1827+
1828+ /* iterate over rules */
1829+ list_for_each_entry(r, &c->rules, list) {
1830+ ret = iptcc_compile_rule(h, repl, r);
1831+ if (ret < 0)
1832+ return ret;
1833+ }
1834+
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;
1845+ else
1846+ foot->target.verdict = RETURN;
1847+ /* set policy-counters */
1848+ memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
1849+
1850+ return 0;
1851+}
1852+
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)
1856+{
1857+ struct rule_head *r;
1858+
1859+ c->head_offset = *offset;
1860+ DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset);
1861+
1862+ if (!iptcc_is_builtin(c)) {
1863+ /* Chain has header */
1864+ *offset += sizeof(STRUCT_ENTRY)
1865+ + ALIGN(sizeof(struct ipt_error_target));
1866+ (*num)++;
1867+ }
1868+
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;
1872+ r->index = *num;
1873+ *offset += r->size;
1874+ (*num)++;
1875+ }
1876+
1877+ DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num,
1878+ *offset, *num);
1879+ c->foot_offset = *offset;
1880+ c->foot_index = *num;
1881+ *offset += sizeof(STRUCT_ENTRY)
1882+ + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1883+ (*num)++;
1884+
1885+ return 1;
1886+}
1887+
1888+/* put the pieces back together again */
1889+static int iptcc_compile_table_prep(TC_HANDLE_T h, unsigned int *size)
1890+{
1891+ struct chain_head *c;
1892+ unsigned int offset = 0, num = 0;
1893+ int ret = 0;
1894+
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);
1898+ if (ret < 0)
1899+ return ret;
1900 }
1901
1902- return (const char *)GET_TARGET(e)->data;
1903+ /* Append one error rule at end of chain */
1904+ num++;
1905+ offset += sizeof(STRUCT_ENTRY)
1906+ + ALIGN(sizeof(struct ipt_error_target));
1907+
1908+ /* ruleset size is now in offset */
1909+ *size = offset;
1910+ return num;
1911 }
1912
1913+static int iptcc_compile_table(TC_HANDLE_T h, STRUCT_REPLACE *repl)
1914+{
1915+ struct chain_head *c;
1916+ struct iptcb_chain_error *error;
1917+
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);
1921+ if (ret < 0)
1922+ return ret;
1923+ }
1924+
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");
1933+
1934+ return 1;
1935+}
1936+
1937+/**********************************************************************
1938+ * EXTERNAL API (operates on cache only)
1939+ **********************************************************************/
1940+
1941 /* Allocate handle of given size */
1942 static TC_HANDLE_T
1943 alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
1944@@ -202,94 +766,139 @@
1945 size_t len;
1946 TC_HANDLE_T h;
1947
1948- len = sizeof(STRUCT_TC_HANDLE)
1949- + size
1950- + num_rules * sizeof(struct counter_map);
1951+ len = sizeof(STRUCT_TC_HANDLE) + size;
1952
1953- if ((h = malloc(len)) == NULL) {
1954+ h = malloc(sizeof(STRUCT_TC_HANDLE));
1955+ if (!h) {
1956 errno = ENOMEM;
1957 return NULL;
1958 }
1959-
1960- h->changed = 0;
1961- h->cache_num_chains = 0;
1962- h->cache_chain_heads = NULL;
1963- h->counter_map = (void *)h
1964- + sizeof(STRUCT_TC_HANDLE)
1965- + size;
1966+ memset(h, 0, sizeof(*h));
1967+ INIT_LIST_HEAD(&h->chains);
1968 strcpy(h->info.name, tablename);
1969- strcpy(h->entries.name, tablename);
1970+
1971+ h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size);
1972+ if (!h->entries)
1973+ goto out_free_handle;
1974+
1975+ strcpy(h->entries->name, tablename);
1976+ h->entries->size = size;
1977
1978 return h;
1979+
1980+out_free_handle:
1981+ free(h);
1982+
1983+ return NULL;
1984 }
1985
1986+
1987 TC_HANDLE_T
1988 TC_INIT(const char *tablename)
1989 {
1990 TC_HANDLE_T h;
1991 STRUCT_GETINFO info;
1992- unsigned int i;
1993 int tmp;
1994 socklen_t s;
1995
1996 iptc_fn = TC_INIT;
1997
1998- if (sockfd != -1)
1999- close(sockfd);
2000+ if (strlen(tablename) >= TABLE_MAXNAMELEN) {
2001+ errno = EINVAL;
2002+ return NULL;
2003+ }
2004
2005+ if (sockfd_use == 0) {
2006 sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
2007 if (sockfd < 0)
2008 return NULL;
2009+ }
2010+ sockfd_use++;
2011
2012 s = sizeof(info);
2013- if (strlen(tablename) >= TABLE_MAXNAMELEN) {
2014- errno = EINVAL;
2015- return NULL;
2016- }
2017+
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) {
2022+ close(sockfd);
2023+ sockfd = -1;
2024+ }
2025 return NULL;
2026+ }
2027
2028- if ((h = alloc_handle(info.name, info.size, info.num_entries))
2029- == NULL)
2030- return NULL;
2031+ DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
2032+ info.valid_hooks, info.num_entries, info.size);
2033
2034-/* Too hard --RR */
2035-#if 0
2036- sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name);
2037- dynlib = dlopen(pathname, RTLD_NOW);
2038- if (!dynlib) {
2039- errno = ENOENT;
2040- return NULL;
2041+ if ((h = alloc_handle(info.name, info.size, info.num_entries))
2042+ == NULL) {
2043+ if (--sockfd_use == 0) {
2044+ close(sockfd);
2045+ sockfd = -1;
2046 }
2047- h->hooknames = dlsym(dynlib, "hooknames");
2048- if (!h->hooknames) {
2049- errno = ENOENT;
2050 return NULL;
2051 }
2052-#else
2053- h->hooknames = hooknames;
2054-#endif
2055
2056 /* Initialize current state */
2057 h->info = info;
2058- h->new_number = h->info.num_entries;
2059- for (i = 0; i < h->info.num_entries; i++)
2060- h->counter_map[i]
2061- = ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i});
2062
2063- h->entries.size = h->info.size;
2064+ h->entries->size = h->info.size;
2065
2066 tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
2067
2068- if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries,
2069- &tmp) < 0) {
2070- free(h);
2071- return NULL;
2072+ if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
2073+ &tmp) < 0)
2074+ goto error;
2075+
2076+#ifdef IPTC_DEBUG2
2077+ {
2078+ int fd = open("/tmp/libiptc-so_get_entries.blob",
2079+ O_CREAT|O_WRONLY);
2080+ if (fd >= 0) {
2081+ write(fd, h->entries, tmp);
2082+ close(fd);
2083+ }
2084 }
2085+#endif
2086+
2087+ if (parse_table(h) < 0)
2088+ goto error;
2089
2090 CHECK(h);
2091 return h;
2092+error:
2093+ if (--sockfd_use == 0) {
2094+ close(sockfd);
2095+ sockfd = -1;
2096+ }
2097+ TC_FREE(&h);
2098+ return NULL;
2099+}
2100+
2101+void
2102+TC_FREE(TC_HANDLE_T *h)
2103+{
2104+ struct chain_head *c, *tmp;
2105+
2106+ iptc_fn = TC_FREE;
2107+ if (--sockfd_use == 0) {
2108+ close(sockfd);
2109+ sockfd = -1;
2110+ }
2111+
2112+ list_for_each_entry_safe(c, tmp, &(*h)->chains, list) {
2113+ struct rule_head *r, *rtmp;
2114+
2115+ list_for_each_entry_safe(r, rtmp, &c->rules, list) {
2116+ free(r);
2117+ }
2118+
2119+ free(c);
2120+ }
2121+
2122+ free((*h)->entries);
2123+ free(*h);
2124+
2125+ *h = NULL;
2126 }
2127
2128 static inline int
2129@@ -304,11 +913,11 @@
2130 void
2131 TC_DUMP_ENTRIES(const TC_HANDLE_T handle)
2132 {
2133+ iptc_fn = TC_DUMP_ENTRIES;
2134 CHECK(handle);
2135-
2136- printf("libiptc v%s. %u entries, %u bytes.\n",
2137- NETFILTER_VERSION,
2138- handle->new_number, handle->entries.size);
2139+#if 0
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]);
2148
2149- ENTRY_ITERATE(handle->entries.entrytable, handle->entries.size,
2150+ ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size,
2151 dump_entry, handle);
2152-}
2153-
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)
2157-{
2158- unsigned int i;
2159-
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)
2163- return i+1;
2164- }
2165- return 0;
2166-}
2167-
2168-static inline int
2169-add_chain(STRUCT_ENTRY *e, TC_HANDLE_T h, STRUCT_ENTRY **prev)
2170-{
2171- unsigned int builtin;
2172-
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;
2177- return 0;
2178- }
2179-
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
2185- = *prev;
2186-
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
2196- = *prev;
2197-
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
2201- = (void *)e;
2202- h->cache_num_chains++;
2203- }
2204-
2205- *prev = e;
2206- return 0;
2207-}
2208-
2209-static int alphasort(const void *a, const void *b)
2210-{
2211- return strcmp(((struct chain_cache *)a)->name,
2212- ((struct chain_cache *)b)->name);
2213-}
2214-
2215-static int populate_cache(TC_HANDLE_T h)
2216-{
2217- unsigned int i;
2218- STRUCT_ENTRY *prev;
2219-
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) {
2224- errno = ENOMEM;
2225- return 0;
2226- }
2227-
2228- h->cache_num_chains = 0;
2229- h->cache_num_builtins = 0;
2230-
2231- /* Count builtins */
2232- for (i = 0; i < NUMHOOKS; i++) {
2233- if (h->info.valid_hooks & (1 << i))
2234- h->cache_num_builtins++;
2235- }
2236-
2237- prev = NULL;
2238- ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
2239- add_chain, h, &prev);
2240-
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);
2244-
2245- return 1;
2246-}
2247-
2248-/* Returns cache ptr if found, otherwise NULL. */
2249-static struct chain_cache *
2250-find_label(const char *name, TC_HANDLE_T handle)
2251-{
2252- unsigned int i;
2253-
2254- if (handle->cache_chain_heads == NULL
2255- && !populate_cache(handle))
2256- return NULL;
2257-
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];
2262- }
2263-
2264- return NULL;
2265+#endif
2266 }
2267
2268 /* Does this chain exist? */
2269 int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
2270 {
2271- return find_label(chain, handle) != NULL;
2272+ iptc_fn = TC_IS_CHAIN;
2273+ return iptcc_find_label(chain, handle) != NULL;
2274 }
2275
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)
2280 {
2281- unsigned int last_off, off;
2282- STRUCT_ENTRY *e;
2283-
2284- last_off = start;
2285- e = get_entry(handle, start);
2286-
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;
2292- unsigned int i;
2293-
2294- e = get_entry(handle, off);
2295-
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])
2300- return last_off;
2301- }
2302+ struct chain_head *c = handle->chain_iterator_cur;
2303
2304- /* We hit a user chain label */
2305- t = GET_TARGET(e);
2306- if (strcmp(t->u.user.name, ERROR_TARGET) == 0)
2307- return last_off;
2308- }
2309- /* SHOULD NEVER HAPPEN */
2310- fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n",
2311- handle->entries.size, off);
2312- abort();
2313+ if (c->list.next == &handle->chains)
2314+ handle->chain_iterator_cur = NULL;
2315+ else
2316+ handle->chain_iterator_cur =
2317+ list_entry(c->list.next, struct chain_head, list);
2318 }
2319
2320 /* Iterator functions to run through the chains. */
2321 const char *
2322 TC_FIRST_CHAIN(TC_HANDLE_T *handle)
2323 {
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);
2328+
2329+ iptc_fn = TC_FIRST_CHAIN;
2330+
2331+
2332+ if (list_empty(&(*handle)->chains)) {
2333+ DEBUGP(": no chains\n");
2334 return NULL;
2335+ }
2336
2337- (*handle)->cache_chain_iteration
2338- = &(*handle)->cache_chain_heads[0];
2339+ (*handle)->chain_iterator_cur = c;
2340+ iptcc_chain_iterator_advance(*handle);
2341
2342- return (*handle)->cache_chain_iteration->name;
2343+ DEBUGP(": returning `%s'\n", c->name);
2344+ return c->name;
2345 }
2346
2347 /* Iterator functions to run through the chains. Returns NULL at end. */
2348 const char *
2349 TC_NEXT_CHAIN(TC_HANDLE_T *handle)
2350 {
2351- (*handle)->cache_chain_iteration++;
2352+ struct chain_head *c = (*handle)->chain_iterator_cur;
2353
2354- if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads
2355- == (*handle)->cache_num_chains)
2356+ iptc_fn = TC_NEXT_CHAIN;
2357+
2358+ if (!c) {
2359+ DEBUGP(": no more chains\n");
2360 return NULL;
2361+ }
2362
2363- return (*handle)->cache_chain_iteration->name;
2364+ iptcc_chain_iterator_advance(*handle);
2365+
2366+ DEBUGP(": returning `%s'\n", c->name);
2367+ return c->name;
2368 }
2369
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)
2373 {
2374- struct chain_cache *c;
2375+ struct chain_head *c;
2376+ struct rule_head *r;
2377+
2378+ iptc_fn = TC_FIRST_RULE;
2379+
2380+ DEBUGP("first rule(%s): ", chain);
2381
2382- c = find_label(chain, *handle);
2383+ c = iptcc_find_label(chain, *handle);
2384 if (!c) {
2385 errno = ENOENT;
2386 return NULL;
2387 }
2388
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");
2393 return NULL;
2394+ }
2395+
2396+ r = list_entry(c->rules.next, struct rule_head, list);
2397+ (*handle)->rule_iterator_cur = r;
2398+ DEBUGP_C("%p\n", r);
2399
2400- (*handle)->cache_rule_end = c->end;
2401- return c->start;
2402+ return r->entry;
2403 }
2404
2405 /* Returns NULL when rules run out. */
2406 const STRUCT_ENTRY *
2407 TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
2408 {
2409- if ((void *)prev + prev->next_offset
2410- == (void *)(*handle)->cache_rule_end)
2411+ struct rule_head *r;
2412+
2413+ iptc_fn = TC_NEXT_RULE;
2414+ DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
2415+
2416+ if (!(*handle)->rule_iterator_cur) {
2417+ DEBUGP_C("returning NULL\n");
2418+ return NULL;
2419+ }
2420+
2421+ r = list_entry((*handle)->rule_iterator_cur->list.next,
2422+ struct rule_head, list);
2423+
2424+ iptc_fn = TC_NEXT_RULE;
2425+
2426+ DEBUGP_C("next=%p, head=%p...", &r->list,
2427+ &(*handle)->rule_iterator_cur->chain->rules);
2428+
2429+ if (&r->list == &(*handle)->rule_iterator_cur->chain->rules) {
2430+ (*handle)->rule_iterator_cur = NULL;
2431+ DEBUGP_C("finished, returning NULL\n");
2432 return NULL;
2433+ }
2434+
2435+ (*handle)->rule_iterator_cur = r;
2436
2437- return (void *)prev + prev->next_offset;
2438+ /* NOTE: prev is without any influence ! */
2439+ DEBUGP_C("returning rule %p\n", r);
2440+ return r->entry;
2441 }
2442
2443-#if 0
2444 /* How many rules in this chain? */
2445 unsigned int
2446 TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
2447 {
2448- unsigned int off = 0;
2449- STRUCT_ENTRY *start, *end;
2450-
2451+ struct chain_head *c;
2452+ iptc_fn = TC_NUM_RULES;
2453 CHECK(*handle);
2454- if (!find_label(&off, chain, *handle)) {
2455+
2456+ c = iptcc_find_label(chain, *handle);
2457+ if (!c) {
2458 errno = ENOENT;
2459 return (unsigned int)-1;
2460 }
2461
2462- start = get_entry(*handle, off);
2463- end = get_entry(*handle, get_chain_end(*handle, off));
2464-
2465- return entry2index(*handle, end) - entry2index(*handle, start);
2466+ return c->num_rules;
2467 }
2468
2469-/* Get n'th rule in this chain. */
2470 const STRUCT_ENTRY *TC_GET_RULE(const char *chain,
2471 unsigned int n,
2472 TC_HANDLE_T *handle)
2473 {
2474- unsigned int pos = 0, chainindex;
2475+ struct chain_head *c;
2476+ struct rule_head *r;
2477+
2478+ iptc_fn = TC_GET_RULE;
2479
2480 CHECK(*handle);
2481- if (!find_label(&pos, chain, *handle)) {
2482+
2483+ c = iptcc_find_label(chain, *handle);
2484+ if (!c) {
2485 errno = ENOENT;
2486 return NULL;
2487 }
2488
2489- chainindex = entry2index(*handle, get_entry(*handle, pos));
2490-
2491- return index2entry(*handle, chainindex + n);
2492+ r = iptcc_get_rule_num(c, n);
2493+ if (!r)
2494+ return NULL;
2495+ return r->entry;
2496 }
2497-#endif
2498
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)
2503 {
2504- int spos;
2505- unsigned int labelidx;
2506- STRUCT_ENTRY *jumpto;
2507-
2508- /* To avoid const warnings */
2509- STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
2510-
2511- if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0)
2512- return GET_TARGET(e)->u.user.name;
2513-
2514- /* Standard target: evaluate */
2515- spos = *(int *)GET_TARGET(e)->data;
2516- if (spos < 0) {
2517- if (spos == RETURN)
2518+ switch (verdict) {
2519+ case RETURN:
2520 return LABEL_RETURN;
2521- else if (spos == -NF_ACCEPT-1)
2522+ break;
2523+ case -NF_ACCEPT-1:
2524 return LABEL_ACCEPT;
2525- else if (spos == -NF_DROP-1)
2526+ break;
2527+ case -NF_DROP-1:
2528 return LABEL_DROP;
2529- else if (spos == -NF_QUEUE-1)
2530+ break;
2531+ case -NF_QUEUE-1:
2532 return LABEL_QUEUE;
2533-
2534- fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n",
2535- entry2offset(handle, e), handle->entries.size,
2536- spos);
2537+ break;
2538+ default:
2539+ fprintf(stderr, "ERROR: %d not a valid target)\n",
2540+ verdict);
2541 abort();
2542+ break;
2543 }
2544-
2545- jumpto = get_entry(handle, spos);
2546-
2547- /* Fall through rule */
2548- if (jumpto == (void *)e + e->next_offset)
2549- return "";
2550-
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));
2554+ /* not reached */
2555+ return NULL;
2556 }
2557
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)
2562 {
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]);
2566+
2567+ iptc_fn = TC_GET_TARGET;
2568+
2569+ switch(r->type) {
2570+ int spos;
2571+ case IPTCC_R_FALLTHROUGH:
2572+ return "";
2573+ break;
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;
2577+ break;
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);
2582+ break;
2583+ case IPTCC_R_MODULE:
2584+ return GET_TARGET(e)->u.user.name;
2585+ break;
2586+}
2587+ return NULL;
2588 }
2589-
2590 /* Is this a built-in chain? Actually returns hook + 1. */
2591 int
2592 TC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
2593 {
2594- unsigned int i;
2595+ struct chain_head *c;
2596
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)
2601- return i+1;
2602- }
2603+ iptc_fn = TC_BUILTIN;
2604+
2605+ c = iptcc_find_label(chain, handle);
2606+ if (!c) {
2607+ errno = ENOENT;
2608 return 0;
2609 }
2610
2611+ return iptcc_is_builtin(c);
2612+}
2613+
2614 /* Get the policy of a given built-in chain */
2615 const char *
2616 TC_GET_POLICY(const char *chain,
2617 STRUCT_COUNTERS *counters,
2618- TC_HANDLE_T *handle)
2619-{
2620- unsigned int start;
2621- STRUCT_ENTRY *e;
2622- int hook;
2623-
2624- hook = TC_BUILTIN(chain, *handle);
2625- if (hook != 0)
2626- start = (*handle)->info.hook_entry[hook-1];
2627- else
2628- return NULL;
2629-
2630- e = get_entry(*handle, get_chain_end(*handle, start));
2631- *counters = e->counters;
2632-
2633- return target_name(*handle, e);
2634-}
2635-
2636-static int
2637-correct_verdict(STRUCT_ENTRY *e,
2638- char *base,
2639- unsigned int offset, int delta_offset)
2640-{
2641- STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e);
2642- unsigned int curr = (char *)e - base;
2643-
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;
2651- }
2652-
2653- return 0;
2654-}
2655-
2656-/* Adjusts standard verdict jump positions after an insertion/deletion. */
2657-static int
2658-set_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle)
2659-{
2660- ENTRY_ITERATE((*handle)->entries.entrytable,
2661- (*handle)->entries.size,
2662- correct_verdict, (char *)(*handle)->entries.entrytable,
2663- offset, delta_offset);
2664-
2665- set_changed(*handle);
2666- return 1;
2667-}
2668-
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. */
2671-static int
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,
2675- int prepend,
2676 TC_HANDLE_T *handle)
2677 {
2678- TC_HANDLE_T newh;
2679- STRUCT_GETINFO newinfo;
2680- unsigned int i;
2681-
2682- if (offset >= (*handle)->entries.size) {
2683- errno = EINVAL;
2684- return 0;
2685- }
2686+ struct chain_head *c;
2687
2688- newinfo = (*handle)->info;
2689-
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;
2696-
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;
2702- }
2703-
2704- newh = alloc_handle((*handle)->info.name,
2705- (*handle)->entries.size + rules_size,
2706- (*handle)->new_number + num_rules);
2707- if (!newh)
2708- return 0;
2709- newh->info = newinfo;
2710-
2711- /* Copy pre... */
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);
2719-
2720- /* Move counter map. */
2721- /* Copy pre... */
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 });
2733-
2734- newh->new_number = (*handle)->new_number + num_rules;
2735- newh->entries.size = (*handle)->entries.size + rules_size;
2736- newh->hooknames = (*handle)->hooknames;
2737-
2738- if ((*handle)->cache_chain_heads)
2739- free((*handle)->cache_chain_heads);
2740- free(*handle);
2741- *handle = newh;
2742-
2743- return set_verdict(offset, rules_size, handle);
2744-}
2745-
2746-static int
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)
2750-{
2751- unsigned int i;
2752+ iptc_fn = TC_GET_POLICY;
2753
2754- if (offset + rules_size > (*handle)->entries.size) {
2755- errno = EINVAL;
2756- return 0;
2757- }
2758+ DEBUGP("called for chain %s\n", chain);
2759
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);
2770- abort();
2771+ c = iptcc_find_label(chain, *handle);
2772+ if (!c) {
2773+ errno = ENOENT;
2774+ return NULL;
2775 }
2776
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);
2785- abort();
2786- }
2787- }
2788+ if (!iptcc_is_builtin(c))
2789+ return NULL;
2790
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));
2795-
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)));
2801-
2802- /* Fix numbers */
2803- (*handle)->new_number -= num_rules;
2804- (*handle)->entries.size -= rules_size;
2805+ *counters = c->counters;
2806
2807- return set_verdict(offset, -(int)rules_size, handle);
2808+ return standard_target_map(c->verdict);
2809 }
2810
2811 static int
2812-standard_map(STRUCT_ENTRY *e, int verdict)
2813+iptcc_standard_map(struct rule_head *r, int verdict)
2814 {
2815+ STRUCT_ENTRY *e = r->entry;
2816 STRUCT_STANDARD_TARGET *t;
2817
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;
2822
2823+ r->type = IPTCC_R_STANDARD;
2824+
2825 return 1;
2826 }
2827
2828 static int
2829-map_target(const TC_HANDLE_T handle,
2830- STRUCT_ENTRY *e,
2831- unsigned int offset,
2832- STRUCT_ENTRY_TARGET *old)
2833+iptcc_map_target(const TC_HANDLE_T handle,
2834+ struct rule_head *r)
2835 {
2836+ STRUCT_ENTRY *e = r->entry;
2837 STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
2838
2839- /* Save old target (except data, which we don't change, except for
2840- standard case, where we don't care). */
2841- *old = *t;
2842-
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;
2848+ return 1;
2849+ }
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. */
2865 errno = EINVAL;
2866 return 0;
2867 } else {
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);
2872
2873- c = find_label(t->u.user.name, handle);
2874- if (c)
2875- return standard_map(e, entry2offset(handle, c->start));
2876+ c = iptcc_find_label(t->u.user.name, handle);
2877+ if (c) {
2878+ DEBUGP_C("found!\n");
2879+ r->type = IPTCC_R_JUMP;
2880+ r->jump = c;
2881+ c->references++;
2882+ return 1;
2883+}
2884+ DEBUGP_C("not found :(\n");
2885 }
2886
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),
2891 0,
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);
2896 return 1;
2897 }
2898
2899-static void
2900-unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old)
2901-{
2902- STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
2903-
2904- /* Save old target (except data, which we don't change, except for
2905- standard case, where we don't care). */
2906- *t = *old;
2907-}
2908-
2909 /* Insert the entry `fw' in chain `chain' into position `rulenum'. */
2910 int
2911 TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
2912@@ -912,36 +1280,56 @@
2913 unsigned int rulenum,
2914 TC_HANDLE_T *handle)
2915 {
2916- unsigned int chainindex, offset;
2917- STRUCT_ENTRY_TARGET old;
2918- struct chain_cache *c;
2919- STRUCT_ENTRY *tmp;
2920- int ret;
2921+ struct chain_head *c;
2922+ struct rule_head *r;
2923+ struct list_head *prev;
2924
2925 iptc_fn = TC_INSERT_ENTRY;
2926- if (!(c = find_label(chain, *handle))) {
2927+
2928+ if (!(c = iptcc_find_label(chain, *handle))) {
2929 errno = ENOENT;
2930 return 0;
2931 }
2932
2933- chainindex = entry2index(*handle, c->start);
2934-
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) {
2940 errno = E2BIG;
2941 return 0;
2942 }
2943- offset = index2offset(*handle, chainindex + rulenum);
2944
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) {
2952+ prev = &c->rules;
2953+ } else if (rulenum + 1 <= c->num_rules/2) {
2954+ r = iptcc_get_rule_num(c, rulenum + 1);
2955+ prev = &r->list;
2956+ } else {
2957+ r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
2958+ prev = &r->list;
2959+ }
2960+
2961+ if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
2962+ errno = ENOMEM;
2963+ return 0;
2964+ }
2965+
2966+ memcpy(r->entry, e, e->next_offset);
2967+ r->counter_map.maptype = COUNTER_MAP_SET;
2968+
2969+ if (!iptcc_map_target(*handle, r)) {
2970+ free(r);
2971 return 0;
2972+ }
2973+
2974+ list_add_tail(&r->list, prev);
2975+ c->num_rules++;
2976+
2977+ set_changed(*handle);
2978
2979- ret = insert_rules(1, e->next_offset, e, offset,
2980- chainindex + rulenum, rulenum == 0, handle);
2981- unmap_target((STRUCT_ENTRY *)e, &old);
2982- return ret;
2983+ return 1;
2984 }
2985
2986 /* Atomically replace rule `rulenum' in `chain' with `fw'. */
2987@@ -951,40 +1339,47 @@
2988 unsigned int rulenum,
2989 TC_HANDLE_T *handle)
2990 {
2991- unsigned int chainindex, offset;
2992- STRUCT_ENTRY_TARGET old;
2993- struct chain_cache *c;
2994- STRUCT_ENTRY *tmp;
2995- int ret;
2996+ struct chain_head *c;
2997+ struct rule_head *r, *old;
2998
2999 iptc_fn = TC_REPLACE_ENTRY;
3000
3001- if (!(c = find_label(chain, *handle))) {
3002+ if (!(c = iptcc_find_label(chain, *handle))) {
3003 errno = ENOENT;
3004 return 0;
3005 }
3006
3007- chainindex = entry2index(*handle, c->start);
3008-
3009- tmp = index2entry(*handle, chainindex + rulenum);
3010- if (!tmp || tmp >= c->end) {
3011+ if (rulenum >= c->num_rules) {
3012 errno = E2BIG;
3013 return 0;
3014 }
3015
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);
3023+ } else {
3024+ old = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
3025+ }
3026+
3027+ if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
3028+ errno = ENOMEM;
3029 return 0;
3030+ }
3031
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;
3035+
3036+ if (!iptcc_map_target(*handle, r)) {
3037+ free(r);
3038 return 0;
3039+ }
3040+
3041+ list_add(&r->list, &old->list);
3042+ iptcc_delete_rule(old);
3043+
3044+ set_changed(*handle);
3045
3046- ret = insert_rules(1, e->next_offset, e, offset,
3047- chainindex + rulenum, 1, handle);
3048- unmap_target((STRUCT_ENTRY *)e, &old);
3049- return ret;
3050+ return 1;
3051 }
3052
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)
3057 {
3058- struct chain_cache *c;
3059- STRUCT_ENTRY_TARGET old;
3060- int ret;
3061+ struct chain_head *c;
3062+ struct rule_head *r;
3063
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);
3068 errno = ENOENT;
3069 return 0;
3070 }
3071
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);
3076+ errno = ENOMEM;
3077+ return 0;
3078+ }
3079+
3080+ memcpy(r->entry, e, e->next_offset);
3081+ r->counter_map.maptype = COUNTER_MAP_SET;
3082+
3083+ if (!iptcc_map_target(*handle, r)) {
3084+ DEBUGP("unable to map target of rule for chain `%s'\n", chain);
3085+ free(r);
3086 return 0;
3087+ }
3088+
3089+ list_add_tail(&r->list, &c->rules);
3090+ c->num_rules++;
3091+
3092+ set_changed(*handle);
3093
3094- ret = insert_rules(1, e->next_offset, e,
3095- entry2offset(*handle, c->end),
3096- entry2index(*handle, c->end),
3097- 0, handle);
3098- unmap_target((STRUCT_ENTRY *)e, &old);
3099- return ret;
3100+ return 1;
3101 }
3102
3103 static inline int
3104@@ -1044,20 +1450,42 @@
3105 }
3106
3107 static inline int
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)
3113 {
3114 unsigned int i;
3115- for (i = 0; i < tdatasize; i++)
3116- if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
3117+ STRUCT_ENTRY_TARGET *ta, *tb;
3118+
3119+ if (a->type != b->type)
3120+ return 0;
3121+
3122+ ta = GET_TARGET(a->entry);
3123+ tb = GET_TARGET(b->entry);
3124+
3125+ switch (a->type) {
3126+ case IPTCC_R_FALLTHROUGH:
3127 return 1;
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)
3135+ return 0;
3136+ if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
3137+ return 0;
3138
3139+ for (i = 0; i < ta->u.target_size - sizeof(*ta); i++)
3140+ if (((ta->data[i] ^ tb->data[i]) & mask[i]) != 0)
3141 return 0;
3142+ return 1;
3143+ default:
3144+ fprintf(stderr, "ERROR: bad type %i\n", a->type);
3145+ abort();
3146+ }
3147 }
3148
3149-static int
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)
3157 {
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;
3163
3164 iptc_fn = TC_DELETE_ENTRY;
3165- if (!(c = find_label(chain, *handle))) {
3166+ if (!(c = iptcc_find_label(chain, *handle))) {
3167 errno = ENOENT;
3168 return 0;
3169 }
3170
3171- fw = malloc(origfw->next_offset);
3172- if (fw == NULL) {
3173+ /* Create a rule_head from origfw. */
3174+ r = iptcc_alloc_rule(c, origfw->next_offset);
3175+ if (!r) {
3176 errno = ENOMEM;
3177 return 0;
3178 }
3179
3180- for (offset = entry2offset(*handle, c->start);
3181- offset < entry2offset(*handle, c->end);
3182- offset += e->next_offset) {
3183- STRUCT_ENTRY_TARGET discard;
3184-
3185- memcpy(fw, origfw, origfw->next_offset);
3186-
3187- /* FIXME: handle this in is_same --RR */
3188- if (!map_target(*handle, fw, offset, &discard)) {
3189- free(fw);
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);
3194+ free(r);
3195 return 0;
3196 }
3197- e = get_entry(*handle, offset);
3198
3199-#if 0
3200- printf("Deleting:\n");
3201- dump_entry(newe);
3202-#endif
3203- if (is_same(e, fw, matchmask)) {
3204- int ret;
3205- ret = delete_rules(1, e->next_offset,
3206- offset, entry2index(*handle, e),
3207- handle);
3208- free(fw);
3209- return ret;
3210+ list_for_each_entry(i, &c->rules, list) {
3211+ unsigned char *mask;
3212+
3213+ mask = is_same(r->entry, i->entry, matchmask);
3214+ if (!mask)
3215+ continue;
3216+
3217+ if (!target_same(r, i, mask))
3218+ continue;
3219+
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);
3227 }
3228+
3229+ c->num_rules--;
3230+ iptcc_delete_rule(i);
3231+
3232+ set_changed(*handle);
3233+ free(r);
3234+ return 1;
3235 }
3236
3237- free(fw);
3238+ free(r);
3239 errno = ENOENT;
3240 return 0;
3241 }
3242
3243+
3244 /* Delete the rule in position `rulenum' in `chain'. */
3245 int
3246 TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
3247 unsigned int rulenum,
3248 TC_HANDLE_T *handle)
3249 {
3250- unsigned int index;
3251- int ret;
3252- STRUCT_ENTRY *e;
3253- struct chain_cache *c;
3254+ struct chain_head *c;
3255+ struct rule_head *r;
3256
3257 iptc_fn = TC_DELETE_NUM_ENTRY;
3258- if (!(c = find_label(chain, *handle))) {
3259+
3260+ if (!(c = iptcc_find_label(chain, *handle))) {
3261 errno = ENOENT;
3262 return 0;
3263 }
3264
3265- index = entry2index(*handle, c->start) + rulenum;
3266-
3267- if (index >= entry2index(*handle, c->end)) {
3268+ if (rulenum >= c->num_rules) {
3269 errno = E2BIG;
3270 return 0;
3271 }
3272
3273- e = index2entry(*handle, index);
3274- if (e == NULL) {
3275- errno = EINVAL;
3276- return 0;
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);
3280+ } else {
3281+ r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
3282+ }
3283+
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);
3291 }
3292
3293- ret = delete_rules(1, e->next_offset, entry2offset(*handle, e),
3294- index, handle);
3295- return ret;
3296+ c->num_rules--;
3297+ iptcc_delete_rule(r);
3298+
3299+ set_changed(*handle);
3300+
3301+ return 1;
3302 }
3303
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)
3308 {
3309+ iptc_fn = TC_CHECK_PACKET;
3310 errno = ENOSYS;
3311 return NULL;
3312 }
3313@@ -1168,44 +1615,44 @@
3314 int
3315 TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
3316 {
3317- unsigned int startindex, endindex;
3318- struct chain_cache *c;
3319- int ret;
3320+ struct chain_head *c;
3321+ struct rule_head *r, *tmp;
3322
3323 iptc_fn = TC_FLUSH_ENTRIES;
3324- if (!(c = find_label(chain, *handle))) {
3325+ if (!(c = iptcc_find_label(chain, *handle))) {
3326 errno = ENOENT;
3327 return 0;
3328 }
3329- startindex = entry2index(*handle, c->start);
3330- endindex = entry2index(*handle, c->end);
3331
3332- ret = delete_rules(endindex - startindex,
3333- (char *)c->end - (char *)c->start,
3334- entry2offset(*handle, c->start), startindex,
3335- handle);
3336- return ret;
3337+ list_for_each_entry_safe(r, tmp, &c->rules, list) {
3338+ iptcc_delete_rule(r);
3339+ }
3340+
3341+ c->num_rules = 0;
3342+
3343+ set_changed(*handle);
3344+
3345+ return 1;
3346 }
3347
3348 /* Zeroes the counters in a chain. */
3349 int
3350 TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
3351 {
3352- unsigned int i, end;
3353- struct chain_cache *c;
3354+ struct chain_head *c;
3355+ struct rule_head *r;
3356
3357- if (!(c = find_label(chain, *handle))) {
3358+ iptc_fn = TC_ZERO_ENTRIES;
3359+ if (!(c = iptcc_find_label(chain, *handle))) {
3360 errno = ENOENT;
3361 return 0;
3362 }
3363
3364- i = entry2index(*handle, c->start);
3365- end = entry2index(*handle, c->end);
3366-
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;
3373 }
3374+
3375 set_changed(*handle);
3376
3377 return 1;
3378@@ -1216,29 +1663,23 @@
3379 unsigned int rulenum,
3380 TC_HANDLE_T *handle)
3381 {
3382- STRUCT_ENTRY *e;
3383- struct chain_cache *c;
3384- unsigned int chainindex, end;
3385+ struct chain_head *c;
3386+ struct rule_head *r;
3387
3388 iptc_fn = TC_READ_COUNTER;
3389 CHECK(*handle);
3390
3391- if (!(c = find_label(chain, *handle))) {
3392+ if (!(c = iptcc_find_label(chain, *handle))) {
3393 errno = ENOENT;
3394 return NULL;
3395 }
3396
3397- chainindex = entry2index(*handle, c->start);
3398- end = entry2index(*handle, c->end);
3399-
3400- if (chainindex + rulenum > end) {
3401+ if (!(r = iptcc_get_rule_num(c, rulenum))) {
3402 errno = E2BIG;
3403 return NULL;
3404 }
3405
3406- e = index2entry(*handle, chainindex + rulenum);
3407-
3408- return &e->counters;
3409+ return &r->entry[0].counters;
3410 }
3411
3412 int
3413@@ -1246,33 +1687,24 @@
3414 unsigned int rulenum,
3415 TC_HANDLE_T *handle)
3416 {
3417- STRUCT_ENTRY *e;
3418- struct chain_cache *c;
3419- unsigned int chainindex, end;
3420+ struct chain_head *c;
3421+ struct rule_head *r;
3422
3423 iptc_fn = TC_ZERO_COUNTER;
3424 CHECK(*handle);
3425
3426- if (!(c = find_label(chain, *handle))) {
3427+ if (!(c = iptcc_find_label(chain, *handle))) {
3428 errno = ENOENT;
3429 return 0;
3430 }
3431
3432- chainindex = entry2index(*handle, c->start);
3433- end = entry2index(*handle, c->end);
3434-
3435- if (chainindex + rulenum > end) {
3436+ if (!(r = iptcc_get_rule_num(c, rulenum))) {
3437 errno = E2BIG;
3438 return 0;
3439 }
3440
3441- e = index2entry(*handle, chainindex + rulenum);
3442-
3443-// if ((*handle)->counter_map[chainindex + rulenum].maptype
3444-// == COUNTER_MAP_NORMAL_MAP) {
3445- (*handle)->counter_map[chainindex + rulenum].maptype
3446- = COUNTER_MAP_ZEROED;
3447-// }
3448+ if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
3449+ r->counter_map.maptype = COUNTER_MAP_ZEROED;
3450
3451 set_changed(*handle);
3452
3453@@ -1285,30 +1717,25 @@
3454 STRUCT_COUNTERS *counters,
3455 TC_HANDLE_T *handle)
3456 {
3457+ struct chain_head *c;
3458+ struct rule_head *r;
3459 STRUCT_ENTRY *e;
3460- struct chain_cache *c;
3461- unsigned int chainindex, end;
3462
3463 iptc_fn = TC_SET_COUNTER;
3464 CHECK(*handle);
3465
3466- if (!(c = find_label(chain, *handle))) {
3467+ if (!(c = iptcc_find_label(chain, *handle))) {
3468 errno = ENOENT;
3469 return 0;
3470 }
3471
3472- chainindex = entry2index(*handle, c->start);
3473- end = entry2index(*handle, c->end);
3474-
3475- if (chainindex + rulenum > end) {
3476+ if (!(r = iptcc_get_rule_num(c, rulenum))) {
3477 errno = E2BIG;
3478 return 0;
3479 }
3480
3481- e = index2entry(*handle, chainindex + rulenum);
3482-
3483- (*handle)->counter_map[chainindex + rulenum].maptype
3484- = COUNTER_MAP_SET;
3485+ e = r->entry;
3486+ r->counter_map.maptype = COUNTER_MAP_SET;
3487
3488 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
3489
3490@@ -1323,71 +1750,42 @@
3491 int
3492 TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
3493 {
3494- int ret;
3495- struct {
3496- STRUCT_ENTRY head;
3497- struct ipt_error_target name;
3498- STRUCT_ENTRY ret;
3499- STRUCT_STANDARD_TARGET target;
3500- } newc;
3501+ static struct chain_head *c;
3502
3503 iptc_fn = TC_CREATE_CHAIN;
3504
3505 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
3506 QUEUE, RETURN. */
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);
3514 errno = EEXIST;
3515 return 0;
3516 }
3517
3518 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
3519+ DEBUGP("Chain name `%s' too long\n", chain);
3520 errno = EINVAL;
3521 return 0;
3522 }
3523
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);
3532-
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;
3541-
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,
3546- 0, handle);
3547- return ret;
3548-}
3549+ c = iptcc_alloc_chain_head(chain, 0);
3550+ if (!c) {
3551+ DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
3552+ errno = ENOMEM;
3553+ return 0;
3554
3555-static int
3556-count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref)
3557-{
3558- STRUCT_STANDARD_TARGET *t;
3559+ }
3560
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);
3565
3566- if (t->verdict == offset)
3567- (*ref)++;
3568- }
3569+ set_changed(*handle);
3570
3571- return 0;
3572+ return 1;
3573 }
3574
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)
3579 {
3580- struct chain_cache *c;
3581+ struct chain_head *c;
3582
3583- if (!(c = find_label(chain, *handle))) {
3584+ iptc_fn = TC_GET_REFERENCES;
3585+ if (!(c = iptcc_find_label(chain, *handle))) {
3586 errno = ENOENT;
3587 return 0;
3588 }
3589
3590- *ref = 0;
3591- ENTRY_ITERATE((*handle)->entries.entrytable,
3592- (*handle)->entries.size,
3593- count_ref, entry2offset(*handle, c->start), ref);
3594+ *ref = c->references;
3595+
3596 return 1;
3597 }
3598
3599@@ -1413,45 +1810,53 @@
3600 int
3601 TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
3602 {
3603- unsigned int labelidx, labeloff;
3604 unsigned int references;
3605- struct chain_cache *c;
3606- int ret;
3607-
3608- if (!TC_GET_REFERENCES(&references, chain, handle))
3609- return 0;
3610+ struct chain_head *c;
3611
3612 iptc_fn = TC_DELETE_CHAIN;
3613
3614+ if (!(c = iptcc_find_label(chain, *handle))) {
3615+ DEBUGP("cannot find chain `%s'\n", chain);
3616+ errno = ENOENT;
3617+ return 0;
3618+ }
3619+
3620 if (TC_BUILTIN(chain, *handle)) {
3621+ DEBUGP("cannot remove builtin chain `%s'\n", chain);
3622 errno = EINVAL;
3623 return 0;
3624 }
3625
3626- if (references > 0) {
3627- errno = EMLINK;
3628+ if (!TC_GET_REFERENCES(&references, chain, handle)) {
3629+ DEBUGP("cannot get references on chain `%s'\n", chain);
3630 return 0;
3631 }
3632
3633- if (!(c = find_label(chain, *handle))) {
3634- errno = ENOENT;
3635+ if (references > 0) {
3636+ DEBUGP("chain `%s' still has references\n", chain);
3637+ errno = EMLINK;
3638 return 0;
3639 }
3640
3641- if ((void *)c->start != c->end) {
3642+ if (c->num_rules) {
3643+ DEBUGP("chain `%s' is not empty\n", chain);
3644 errno = ENOTEMPTY;
3645 return 0;
3646 }
3647
3648- /* Need label index: preceeds chain start */
3649- labelidx = entry2index(*handle, c->start) - 1;
3650- labeloff = index2offset(*handle, labelidx);
3651-
3652- ret = delete_rules(2,
3653- get_entry(*handle, labeloff)->next_offset
3654- + c->start->next_offset,
3655- labeloff, labelidx, handle);
3656- return ret;
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);
3661+
3662+ list_del(&c->list);
3663+ free(c);
3664+
3665+ DEBUGP("chain `%s' deleted\n", chain);
3666+
3667+ set_changed(*handle);
3668+
3669+ return 1;
3670 }
3671
3672 /* Renames a chain. */
3673@@ -1459,15 +1864,12 @@
3674 const IPT_CHAINLABEL newname,
3675 TC_HANDLE_T *handle)
3676 {
3677- unsigned int labeloff, labelidx;
3678- struct chain_cache *c;
3679- struct ipt_error_target *t;
3680-
3681+ struct chain_head *c;
3682 iptc_fn = TC_RENAME_CHAIN;
3683
3684 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
3685 QUEUE, RETURN. */
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 @@
3692 return 0;
3693 }
3694
3695- if (!(c = find_label(oldname, *handle))
3696+ if (!(c = iptcc_find_label(oldname, *handle))
3697 || TC_BUILTIN(oldname, *handle)) {
3698 errno = ENOENT;
3699 return 0;
3700@@ -1487,15 +1889,8 @@
3701 return 0;
3702 }
3703
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));
3708
3709- t = (struct ipt_error_target *)
3710- GET_TARGET(get_entry(*handle, labeloff));
3711-
3712- memset(t->error, 0, sizeof(t->error));
3713- strcpy(t->error, newname);
3714 set_changed(*handle);
3715
3716 return 1;
3717@@ -1508,51 +1903,37 @@
3718 STRUCT_COUNTERS *counters,
3719 TC_HANDLE_T *handle)
3720 {
3721- unsigned int hook;
3722- unsigned int policyoff, ctrindex;
3723- STRUCT_ENTRY *e;
3724- STRUCT_STANDARD_TARGET *t;
3725+ struct chain_head *c;
3726
3727 iptc_fn = TC_SET_POLICY;
3728- /* Figure out which chain. */
3729- hook = TC_BUILTIN(chain, *handle);
3730- if (hook == 0) {
3731+
3732+ if (!(c = iptcc_find_label(chain, *handle))) {
3733+ DEBUGP("cannot find chain `%s'\n", chain);
3734 errno = ENOENT;
3735 return 0;
3736- } else
3737- hook--;
3738+ }
3739
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);
3746+ errno = ENOENT;
3747 return 0;
3748 }
3749
3750- e = get_entry(*handle, policyoff);
3751- t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
3752-
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;
3759 else {
3760 errno = EINVAL;
3761 return 0;
3762 }
3763
3764- ctrindex = entry2index(*handle, e);
3765-
3766 if (counters) {
3767 /* set byte and packet counters */
3768- memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
3769-
3770- (*handle)->counter_map[ctrindex].maptype
3771- = COUNTER_MAP_SET;
3772-
3773+ memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS));
3774+ c->counter_map.maptype = COUNTER_MAP_SET;
3775 } else {
3776- (*handle)->counter_map[ctrindex]
3777- = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
3778+ c->counter_map.maptype = COUNTER_MAP_NOMAP;
3779 }
3780
3781 set_changed(*handle);
3782@@ -1575,31 +1956,100 @@
3783 answer->bcnt = a->bcnt - b->bcnt;
3784 }
3785
3786+
3787+static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters,
3788+ unsigned int index)
3789+{
3790+ newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0});
3791+ DEBUGP_C("NOMAP => zero\n");
3792+}
3793+
3794+static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
3795+ STRUCT_REPLACE *repl,
3796+ unsigned int index,
3797+ unsigned int mappos)
3798+{
3799+ /* Original read: X.
3800+ * Atomic read on replacement: X + Y.
3801+ * Currently in kernel: Z.
3802+ * Want in kernel: X + Y + Z.
3803+ * => Add in X + Y
3804+ * => Add in replacement read.
3805+ */
3806+ newcounters->counters[index] = repl->counters[mappos];
3807+ DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
3808+}
3809+
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)
3815+{
3816+ /* Original read: X.
3817+ * Atomic read on replacement: X + Y.
3818+ * Currently in kernel: Z.
3819+ * Want in kernel: Y + Z.
3820+ * => Add in Y.
3821+ * => Add in (replacement read - original read).
3822+ */
3823+ subtract_counters(&newcounters->counters[index],
3824+ &repl->counters[mappos],
3825+ counters);
3826+ DEBUGP_C("ZEROED => mappos %u\n", mappos);
3827+}
3828+
3829+static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
3830+ unsigned int index,
3831+ STRUCT_COUNTERS *counters)
3832+{
3833+ /* Want to set counter (iptables-restore) */
3834+
3835+ memcpy(&newcounters->counters[index], counters,
3836+ sizeof(STRUCT_COUNTERS));
3837+
3838+ DEBUGP_C("SET\n");
3839+}
3840+
3841+
3842 int
3843 TC_COMMIT(TC_HANDLE_T *handle)
3844 {
3845 /* Replace, then map back the counters. */
3846 STRUCT_REPLACE *repl;
3847 STRUCT_COUNTERS_INFO *newcounters;
3848- unsigned int i;
3849- size_t counterlen
3850- = sizeof(STRUCT_COUNTERS_INFO)
3851- + sizeof(STRUCT_COUNTERS) * (*handle)->new_number;
3852+ struct chain_head *c;
3853+ int ret;
3854+ size_t counterlen;
3855+ int new_number;
3856+ unsigned int new_size;
3857
3858+ iptc_fn = TC_COMMIT;
3859 CHECK(*handle);
3860-#if 0
3861- TC_DUMP_ENTRIES(*handle);
3862-#endif
3863
3864 /* Don't commit if nothing changed. */
3865 if (!(*handle)->changed)
3866 goto finished;
3867
3868- repl = malloc(sizeof(*repl) + (*handle)->entries.size);
3869+ new_number = iptcc_compile_table_prep(*handle, &new_size);
3870+ if (new_number < 0) {
3871+ errno = ENOMEM;
3872+ return 0;
3873+ }
3874+
3875+ repl = malloc(sizeof(*repl) + new_size);
3876 if (!repl) {
3877 errno = ENOMEM;
3878 return 0;
3879 }
3880+ memset(repl, 0, sizeof(*repl) + new_size);
3881+
3882+#if 0
3883+ TC_DUMP_ENTRIES(*handle);
3884+#endif
3885+
3886+ counterlen = sizeof(STRUCT_COUNTERS_INFO)
3887+ + sizeof(STRUCT_COUNTERS) * new_number;
3888
3889 /* These are the old counters we will get from kernel */
3890 repl->counters = malloc(sizeof(STRUCT_COUNTERS)
3891@@ -1609,7 +2059,6 @@
3892 errno = ENOMEM;
3893 return 0;
3894 }
3895-
3896 /* These are the counters we're going to put back, later. */
3897 newcounters = malloc(counterlen);
3898 if (!newcounters) {
3899@@ -1618,21 +2067,40 @@
3900 errno = ENOMEM;
3901 return 0;
3902 }
3903+ memset(newcounters, 0, counterlen);
3904
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;
3914+
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);
3919+
3920+ DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
3921+ repl->num_entries, repl->size, repl->num_counters);
3922+
3923+ ret = iptcc_compile_table(*handle, repl);
3924+ if (ret < 0) {
3925+ errno = ret;
3926+ free(repl->counters);
3927+ free(repl);
3928+ return 0;
3929+ }
3930+
3931+
3932+#ifdef IPTC_DEBUG2
3933+ {
3934+ int fd = open("/tmp/libiptc-so_set_replace.blob",
3935+ O_CREAT|O_WRONLY);
3936+ if (fd >= 0) {
3937+ write(fd, repl, sizeof(*repl) + repl->size);
3938+ close(fd);
3939+ }
3940+ }
3941+#endif
3942
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);
3947 free(repl);
3948 free(newcounters);
3949@@ -1641,49 +2109,64 @@
3950
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;
3958+
3959+ list_for_each_entry(c, &(*handle)->chains, list) {
3960+ struct rule_head *r;
3961+
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);
3968+ break;
3969+ case COUNTER_MAP_NORMAL_MAP:
3970+ counters_normal_map(newcounters, repl,
3971+ c->foot_index,
3972+ c->counter_map.mappos);
3973+ break;
3974+ case COUNTER_MAP_ZEROED:
3975+ counters_map_zeroed(newcounters, repl,
3976+ c->foot_index,
3977+ c->counter_map.mappos,
3978+ &c->counters);
3979+ break;
3980+ case COUNTER_MAP_SET:
3981+ counters_map_set(newcounters, c->foot_index,
3982+ &c->counters);
3983+ break;
3984+ }
3985+ }
3986+
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);
3994 break;
3995
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.
4001- * => Add in X + Y
4002- * => Add in replacement read.
4003- */
4004- newcounters->counters[i] = repl->counters[mappos];
4005+ counters_normal_map(newcounters, repl,
4006+ r->index,
4007+ r->counter_map.mappos);
4008 break;
4009
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.
4015- * => Add in Y.
4016- * => Add in (replacement read - original read).
4017- */
4018- subtract_counters(&newcounters->counters[i],
4019- &repl->counters[mappos],
4020- &index2entry(*handle, i)->counters);
4021+ counters_map_zeroed(newcounters, repl,
4022+ r->index,
4023+ r->counter_map.mappos,
4024+ &r->entry->counters);
4025 break;
4026
4027 case COUNTER_MAP_SET:
4028- /* Want to set counter (iptables-restore) */
4029-
4030- memcpy(&newcounters->counters[i],
4031- &index2entry(*handle, i)->counters,
4032- sizeof(STRUCT_COUNTERS));
4033-
4034+ counters_map_set(newcounters, r->index,
4035+ &r->entry->counters);
4036 break;
4037 }
4038 }
4039+ }
4040+
4041
4042 #ifdef KERNEL_64_USERSPACE_32
4043 {
4044@@ -1696,10 +2179,21 @@
4045 "counters alignment incorrect! Mail rusty!\n");
4046 abort();
4047 }
4048- *kernptr = &newcounters->counters;
4049+ *kernptr = newcounters->counters;
4050 }
4051 #endif /* KERNEL_64_USERSPACE_32 */
4052
4053+#ifdef IPTC_DEBUG2
4054+ {
4055+ int fd = open("/tmp/libiptc-so_set_add_counters.blob",
4056+ O_CREAT|O_WRONLY);
4057+ if (fd >= 0) {
4058+ write(fd, newcounters, counterlen);
4059+ close(fd);
4060+ }
4061+ }
4062+#endif
4063+
4064 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
4065 newcounters, counterlen) < 0) {
4066 free(repl->counters);
4067@@ -1713,10 +2207,7 @@
4068 free(newcounters);
4069
4070 finished:
4071- if ((*handle)->cache_chain_heads)
4072- free((*handle)->cache_chain_heads);
4073- free(*handle);
4074- *handle = NULL;
4075+ TC_FREE(handle);
4076 return 1;
4077 }
4078
4079diff -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
4082@@ -1,7 +1,3 @@
4083-#ifndef NETFILTER_VERSION
4084-#define NETFILTER_VERSION "1.2.5"
4085-#endif
4086-
4087 #ifndef _LIBIPTC_H
4088 #define _LIBIPTC_H
4089 /* Library which manipulates filtering rules. */
4090@@ -38,6 +34,9 @@
4091 /* Take a snapshot of the rules. Returns NULL on error. */
4092 iptc_handle_t iptc_init(const char *tablename);
4093
4094+/* Cleanup after iptc_init(). */
4095+void iptc_free(iptc_handle_t *h);
4096+
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);
4100diff -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
4103@@ -0,0 +1,723 @@
4104+#ifndef _LINUX_LIST_H
4105+#define _LINUX_LIST_H
4106+
4107+#undef offsetof
4108+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
4109+
4110+/**
4111+ * container_of - cast a member of a structure out to the containing structure
4112+ *
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.
4116+ *
4117+ */
4118+#define container_of(ptr, type, member) ({ \
4119+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
4120+ (type *)( (char *)__mptr - offsetof(type,member) );})
4121+
4122+/*
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.
4125+ */
4126+#define typecheck(type,x) \
4127+({ type __dummy; \
4128+ typeof(x) __dummy2; \
4129+ (void)(&__dummy == &__dummy2); \
4130+ 1; \
4131+})
4132+
4133+#define prefetch(x) 1
4134+
4135+/* empty define to make this work in userspace -HW */
4136+#define smp_wmb()
4137+
4138+/*
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.
4142+ */
4143+#define LIST_POISON1 ((void *) 0x00100100)
4144+#define LIST_POISON2 ((void *) 0x00200200)
4145+
4146+/*
4147+ * Simple doubly linked list implementation.
4148+ *
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.
4154+ */
4155+
4156+struct list_head {
4157+ struct list_head *next, *prev;
4158+};
4159+
4160+#define LIST_HEAD_INIT(name) { &(name), &(name) }
4161+
4162+#define LIST_HEAD(name) \
4163+ struct list_head name = LIST_HEAD_INIT(name)
4164+
4165+#define INIT_LIST_HEAD(ptr) do { \
4166+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
4167+} while (0)
4168+
4169+/*
4170+ * Insert a new entry between two known consecutive entries.
4171+ *
4172+ * This is only for internal list manipulation where we know
4173+ * the prev/next entries already!
4174+ */
4175+static inline void __list_add(struct list_head *new,
4176+ struct list_head *prev,
4177+ struct list_head *next)
4178+{
4179+ next->prev = new;
4180+ new->next = next;
4181+ new->prev = prev;
4182+ prev->next = new;
4183+}
4184+
4185+/**
4186+ * list_add - add a new entry
4187+ * @new: new entry to be added
4188+ * @head: list head to add it after
4189+ *
4190+ * Insert a new entry after the specified head.
4191+ * This is good for implementing stacks.
4192+ */
4193+static inline void list_add(struct list_head *new, struct list_head *head)
4194+{
4195+ __list_add(new, head, head->next);
4196+}
4197+
4198+/**
4199+ * list_add_tail - add a new entry
4200+ * @new: new entry to be added
4201+ * @head: list head to add it before
4202+ *
4203+ * Insert a new entry before the specified head.
4204+ * This is useful for implementing queues.
4205+ */
4206+static inline void list_add_tail(struct list_head *new, struct list_head *head)
4207+{
4208+ __list_add(new, head->prev, head);
4209+}
4210+
4211+/*
4212+ * Insert a new entry between two known consecutive entries.
4213+ *
4214+ * This is only for internal list manipulation where we know
4215+ * the prev/next entries already!
4216+ */
4217+static inline void __list_add_rcu(struct list_head * new,
4218+ struct list_head * prev, struct list_head * next)
4219+{
4220+ new->next = next;
4221+ new->prev = prev;
4222+ smp_wmb();
4223+ next->prev = new;
4224+ prev->next = new;
4225+}
4226+
4227+/**
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
4231+ *
4232+ * Insert a new entry after the specified head.
4233+ * This is good for implementing stacks.
4234+ *
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().
4242+ */
4243+static inline void list_add_rcu(struct list_head *new, struct list_head *head)
4244+{
4245+ __list_add_rcu(new, head, head->next);
4246+}
4247+
4248+/**
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
4252+ *
4253+ * Insert a new entry before the specified head.
4254+ * This is useful for implementing queues.
4255+ *
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().
4263+ */
4264+static inline void list_add_tail_rcu(struct list_head *new,
4265+ struct list_head *head)
4266+{
4267+ __list_add_rcu(new, head->prev, head);
4268+}
4269+
4270+/*
4271+ * Delete a list entry by making the prev/next entries
4272+ * point to each other.
4273+ *
4274+ * This is only for internal list manipulation where we know
4275+ * the prev/next entries already!
4276+ */
4277+static inline void __list_del(struct list_head * prev, struct list_head * next)
4278+{
4279+ next->prev = prev;
4280+ prev->next = next;
4281+}
4282+
4283+/**
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.
4288+ */
4289+static inline void list_del(struct list_head *entry)
4290+{
4291+ __list_del(entry->prev, entry->next);
4292+ entry->next = LIST_POISON1;
4293+ entry->prev = LIST_POISON2;
4294+}
4295+
4296+/**
4297+ * list_del_rcu - deletes entry from list without re-initialization
4298+ * @entry: the element to delete from the list.
4299+ *
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.
4303+ *
4304+ * In particular, it means that we can not poison the forward
4305+ * pointers that may still be used for walking the list.
4306+ *
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().
4314+ *
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.
4319+ */
4320+static inline void list_del_rcu(struct list_head *entry)
4321+{
4322+ __list_del(entry->prev, entry->next);
4323+ entry->prev = LIST_POISON2;
4324+}
4325+
4326+/**
4327+ * list_del_init - deletes entry from list and reinitialize it.
4328+ * @entry: the element to delete from the list.
4329+ */
4330+static inline void list_del_init(struct list_head *entry)
4331+{
4332+ __list_del(entry->prev, entry->next);
4333+ INIT_LIST_HEAD(entry);
4334+}
4335+
4336+/**
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
4340+ */
4341+static inline void list_move(struct list_head *list, struct list_head *head)
4342+{
4343+ __list_del(list->prev, list->next);
4344+ list_add(list, head);
4345+}
4346+
4347+/**
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
4351+ */
4352+static inline void list_move_tail(struct list_head *list,
4353+ struct list_head *head)
4354+{
4355+ __list_del(list->prev, list->next);
4356+ list_add_tail(list, head);
4357+}
4358+
4359+/**
4360+ * list_empty - tests whether a list is empty
4361+ * @head: the list to test.
4362+ */
4363+static inline int list_empty(const struct list_head *head)
4364+{
4365+ return head->next == head;
4366+}
4367+
4368+/**
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
4372+ *
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.
4377+ *
4378+ * @head: the list to test.
4379+ */
4380+static inline int list_empty_careful(const struct list_head *head)
4381+{
4382+ struct list_head *next = head->next;
4383+ return (next == head) && (next == head->prev);
4384+}
4385+
4386+static inline void __list_splice(struct list_head *list,
4387+ struct list_head *head)
4388+{
4389+ struct list_head *first = list->next;
4390+ struct list_head *last = list->prev;
4391+ struct list_head *at = head->next;
4392+
4393+ first->prev = head;
4394+ head->next = first;
4395+
4396+ last->next = at;
4397+ at->prev = last;
4398+}
4399+
4400+/**
4401+ * list_splice - join two lists
4402+ * @list: the new list to add.
4403+ * @head: the place to add it in the first list.
4404+ */
4405+static inline void list_splice(struct list_head *list, struct list_head *head)
4406+{
4407+ if (!list_empty(list))
4408+ __list_splice(list, head);
4409+}
4410+
4411+/**
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.
4415+ *
4416+ * The list at @list is reinitialised
4417+ */
4418+static inline void list_splice_init(struct list_head *list,
4419+ struct list_head *head)
4420+{
4421+ if (!list_empty(list)) {
4422+ __list_splice(list, head);
4423+ INIT_LIST_HEAD(list);
4424+ }
4425+}
4426+
4427+/**
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.
4432+ */
4433+#define list_entry(ptr, type, member) \
4434+ container_of(ptr, type, member)
4435+
4436+/**
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.
4440+ */
4441+#define list_for_each(pos, head) \
4442+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
4443+ pos = pos->next, prefetch(pos->next))
4444+
4445+/**
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.
4449+ *
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.
4454+ */
4455+#define __list_for_each(pos, head) \
4456+ for (pos = (head)->next; pos != (head); pos = pos->next)
4457+
4458+/**
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.
4462+ */
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))
4466+
4467+/**
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.
4472+ */
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)
4476+
4477+/**
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.
4482+ */
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))
4489+
4490+/**
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.
4495+ */
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))
4502+
4503+/**
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.
4509+ */
4510+#define list_prepare_entry(pos, head, member) \
4511+ ((pos) ? : list_entry(head, typeof(*pos), member))
4512+
4513+/**
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.
4519+ */
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))
4526+
4527+/**
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.
4533+ */
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))
4539+
4540+/**
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.
4544+ *
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().
4548+ */
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))
4552+
4553+#define __list_for_each_rcu(pos, head) \
4554+ for (pos = (head)->next; pos != (head); \
4555+ pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
4556+
4557+/**
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.
4563+ *
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().
4567+ */
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)
4571+
4572+/**
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.
4577+ *
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().
4581+ */
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))
4589+
4590+
4591+/**
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.
4596+ *
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().
4600+ */
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))
4604+
4605+/*
4606+ * Double linked lists with a single pointer list head.
4607+ * Mostly useful for hash tables where the two pointer list head is
4608+ * too wasteful.
4609+ * You lose the ability to access the tail in O(1).
4610+ */
4611+
4612+struct hlist_head {
4613+ struct hlist_node *first;
4614+};
4615+
4616+struct hlist_node {
4617+ struct hlist_node *next, **pprev;
4618+};
4619+
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)
4624+
4625+static inline int hlist_unhashed(const struct hlist_node *h)
4626+{
4627+ return !h->pprev;
4628+}
4629+
4630+static inline int hlist_empty(const struct hlist_head *h)
4631+{
4632+ return !h->first;
4633+}
4634+
4635+static inline void __hlist_del(struct hlist_node *n)
4636+{
4637+ struct hlist_node *next = n->next;
4638+ struct hlist_node **pprev = n->pprev;
4639+ *pprev = next;
4640+ if (next)
4641+ next->pprev = pprev;
4642+}
4643+
4644+static inline void hlist_del(struct hlist_node *n)
4645+{
4646+ __hlist_del(n);
4647+ n->next = LIST_POISON1;
4648+ n->pprev = LIST_POISON2;
4649+}
4650+
4651+/**
4652+ * hlist_del_rcu - deletes entry from hash list without re-initialization
4653+ * @n: the element to delete from the hash list.
4654+ *
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.
4658+ *
4659+ * In particular, it means that we can not poison the forward
4660+ * pointers that may still be used for walking the hash list.
4661+ *
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().
4669+ */
4670+static inline void hlist_del_rcu(struct hlist_node *n)
4671+{
4672+ __hlist_del(n);
4673+ n->pprev = LIST_POISON2;
4674+}
4675+
4676+static inline void hlist_del_init(struct hlist_node *n)
4677+{
4678+ if (n->pprev) {
4679+ __hlist_del(n);
4680+ INIT_HLIST_NODE(n);
4681+ }
4682+}
4683+
4684+#define hlist_del_rcu_init hlist_del_init
4685+
4686+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
4687+{
4688+ struct hlist_node *first = h->first;
4689+ n->next = first;
4690+ if (first)
4691+ first->pprev = &n->next;
4692+ h->first = n;
4693+ n->pprev = &h->first;
4694+}
4695+
4696+
4697+/**
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.
4702+ *
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().
4713+ *
4714+ * OK, so why don't we have an hlist_for_each_entry_rcu()???
4715+ */
4716+static inline void hlist_add_head_rcu(struct hlist_node *n,
4717+ struct hlist_head *h)
4718+{
4719+ struct hlist_node *first = h->first;
4720+ n->next = first;
4721+ n->pprev = &h->first;
4722+ smp_wmb();
4723+ if (first)
4724+ first->pprev = &n->next;
4725+ h->first = n;
4726+}
4727+
4728+/* next must be != NULL */
4729+static inline void hlist_add_before(struct hlist_node *n,
4730+ struct hlist_node *next)
4731+{
4732+ n->pprev = next->pprev;
4733+ n->next = next;
4734+ next->pprev = &n->next;
4735+ *(n->pprev) = n;
4736+}
4737+
4738+static inline void hlist_add_after(struct hlist_node *n,
4739+ struct hlist_node *next)
4740+{
4741+ next->next = n->next;
4742+ n->next = next;
4743+ next->pprev = &n->next;
4744+
4745+ if(next->next)
4746+ next->next->pprev = &next->next;
4747+}
4748+
4749+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
4750+
4751+#define hlist_for_each(pos, head) \
4752+ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
4753+ pos = pos->next)
4754+
4755+#define hlist_for_each_safe(pos, n, head) \
4756+ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
4757+ pos = n)
4758+
4759+/**
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.
4765+ */
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;}); \
4770+ pos = pos->next)
4771+
4772+/**
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.
4777+ */
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;}); \
4782+ pos = pos->next)
4783+
4784+/**
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.
4789+ */
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;}); \
4793+ pos = pos->next)
4794+
4795+/**
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.
4802+ */
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;}); \
4807+ pos = n)
4808+
4809+/**
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.
4815+ *
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().
4819+ */
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; }) )
4825+
4826+#endif