]> git.ipfire.org Git - ipfire-2.x.git/blob - src/patches/ipac-ng-1.31-iptables-1.3.1.patch
Webinterface-Bilder neu gemacht | IPAC-NG-Patches installiert | Berkeley-DB installiert
[ipfire-2.x.git] / src / patches / ipac-ng-1.31-iptables-1.3.1.patch
1 diff -Nur ipac-ng-1.31.orig/agents/iptables/iptables.c ipac-ng-1.31/agents/iptables/iptables.c
2 --- ipac-ng-1.31.orig/agents/iptables/iptables.c 2004-06-27 22:08:54.000000000 +0000
3 +++ ipac-ng-1.31/agents/iptables/iptables.c 2006-01-11 21:49:40.000000000 +0000
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
814 diff -Nur ipac-ng-1.31.orig/agents/iptables/libip4tc.c ipac-ng-1.31/agents/iptables/libip4tc.c
815 --- ipac-ng-1.31.orig/agents/iptables/libip4tc.c 2003-07-06 10:33:23.000000000 +0000
816 +++ ipac-ng-1.31/agents/iptables/libip4tc.c 2006-01-11 21:51:46.000000000 +0000
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
1118 diff -Nur ipac-ng-1.31.orig/agents/iptables/libiptc.c ipac-ng-1.31/agents/iptables/libiptc.c
1119 --- ipac-ng-1.31.orig/agents/iptables/libiptc.c 2003-07-06 11:34:52.000000000 +0000
1120 +++ ipac-ng-1.31/agents/iptables/libiptc.c 2006-01-10 21:01:39.000000000 +0000
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
4079 diff -Nur ipac-ng-1.31.orig/agents/iptables/libiptc.h ipac-ng-1.31/agents/iptables/libiptc.h
4080 --- ipac-ng-1.31.orig/agents/iptables/libiptc.h 2003-07-06 10:33:17.000000000 +0000
4081 +++ ipac-ng-1.31/agents/iptables/libiptc.h 2006-01-10 21:01:39.000000000 +0000
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);
4100 diff -Nur ipac-ng-1.31.orig/agents/iptables/linux_list.h ipac-ng-1.31/agents/iptables/linux_list.h
4101 --- ipac-ng-1.31.orig/agents/iptables/linux_list.h 1970-01-01 00:00:00.000000000 +0000
4102 +++ ipac-ng-1.31/agents/iptables/linux_list.h 2006-01-10 21:01:39.000000000 +0000
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