make string_to_number() static
[jleu-ebtables.git] / communication.c
blobb4a1739595ab4a0a2b1d22643eddd27bc71d6877
1 /*
2 * communication.c, v2.0 July 2002
4 * Author: Bart De Schuymer
6 */
8 /*
9 * All the userspace/kernel communication is in this file.
10 * The other code should not have to know anything about the way the
11 * kernel likes the structure of the table data.
12 * The other code works with linked lists. So, the translation is done here.
15 #include <getopt.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <sys/socket.h>
23 #include "include/ebtables_u.h"
25 extern char* hooknames[NF_BR_NUMHOOKS];
27 #ifdef KERNEL_64_USERSPACE_32
28 #define sparc_cast (uint64_t)
29 #else
30 #define sparc_cast
31 #endif
33 int sockfd = -1;
35 static int get_sockfd()
37 int ret = 0;
38 if (sockfd == -1) {
39 sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
40 if (sockfd < 0) {
41 ebt_print_error("Problem getting a socket, "
42 "you probably don't have the right "
43 "permissions");
44 ret = -1;
47 return ret;
50 static struct ebt_replace *translate_user2kernel(struct ebt_u_replace *u_repl)
52 struct ebt_replace *new;
53 struct ebt_u_entry *e;
54 struct ebt_u_match_list *m_l;
55 struct ebt_u_watcher_list *w_l;
56 struct ebt_u_entries *entries;
57 char *p, *base;
58 int i, j;
59 unsigned int entries_size = 0, *chain_offsets;
61 new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
62 if (!new)
63 ebt_print_memory();
64 new->valid_hooks = u_repl->valid_hooks;
65 strcpy(new->name, u_repl->name);
66 new->nentries = u_repl->nentries;
67 new->num_counters = u_repl->num_counters;
68 new->counters = sparc_cast u_repl->counters;
69 chain_offsets = (unsigned int *)malloc(u_repl->num_chains * sizeof(unsigned int));
70 /* Determine size */
71 for (i = 0; i < u_repl->num_chains; i++) {
72 if (!(entries = u_repl->chains[i]))
73 continue;
74 chain_offsets[i] = entries_size;
75 entries_size += sizeof(struct ebt_entries);
76 j = 0;
77 e = entries->entries->next;
78 while (e != entries->entries) {
79 j++;
80 entries_size += sizeof(struct ebt_entry);
81 m_l = e->m_list;
82 while (m_l) {
83 entries_size += m_l->m->match_size +
84 sizeof(struct ebt_entry_match);
85 m_l = m_l->next;
87 w_l = e->w_list;
88 while (w_l) {
89 entries_size += w_l->w->watcher_size +
90 sizeof(struct ebt_entry_watcher);
91 w_l = w_l->next;
93 entries_size += e->t->target_size +
94 sizeof(struct ebt_entry_target);
95 e = e->next;
97 /* A little sanity check */
98 if (j != entries->nentries)
99 ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j,
100 entries->nentries, entries->name);
103 new->entries_size = entries_size;
104 p = (char *)malloc(entries_size);
105 if (!p)
106 ebt_print_memory();
108 /* Put everything in one block */
109 new->entries = sparc_cast p;
110 for (i = 0; i < u_repl->num_chains; i++) {
111 struct ebt_entries *hlp;
113 hlp = (struct ebt_entries *)p;
114 if (!(entries = u_repl->chains[i]))
115 continue;
116 if (i < NF_BR_NUMHOOKS)
117 new->hook_entry[i] = sparc_cast hlp;
118 hlp->nentries = entries->nentries;
119 hlp->policy = entries->policy;
120 strcpy(hlp->name, entries->name);
121 hlp->counter_offset = entries->counter_offset;
122 hlp->distinguisher = 0; /* Make the kernel see the light */
123 p += sizeof(struct ebt_entries);
124 e = entries->entries->next;
125 while (e != entries->entries) {
126 struct ebt_entry *tmp = (struct ebt_entry *)p;
128 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
129 tmp->invflags = e->invflags;
130 tmp->ethproto = e->ethproto;
131 strcpy(tmp->in, e->in);
132 strcpy(tmp->out, e->out);
133 strcpy(tmp->logical_in, e->logical_in);
134 strcpy(tmp->logical_out, e->logical_out);
135 memcpy(tmp->sourcemac, e->sourcemac,
136 sizeof(tmp->sourcemac));
137 memcpy(tmp->sourcemsk, e->sourcemsk,
138 sizeof(tmp->sourcemsk));
139 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
140 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
142 base = p;
143 p += sizeof(struct ebt_entry);
144 m_l = e->m_list;
145 while (m_l) {
146 memcpy(p, m_l->m, m_l->m->match_size +
147 sizeof(struct ebt_entry_match));
148 p += m_l->m->match_size +
149 sizeof(struct ebt_entry_match);
150 m_l = m_l->next;
152 tmp->watchers_offset = p - base;
153 w_l = e->w_list;
154 while (w_l) {
155 memcpy(p, w_l->w, w_l->w->watcher_size +
156 sizeof(struct ebt_entry_watcher));
157 p += w_l->w->watcher_size +
158 sizeof(struct ebt_entry_watcher);
159 w_l = w_l->next;
161 tmp->target_offset = p - base;
162 memcpy(p, e->t, e->t->target_size +
163 sizeof(struct ebt_entry_target));
164 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
165 struct ebt_standard_target *st =
166 (struct ebt_standard_target *)p;
167 /* Translate the jump to a udc */
168 if (st->verdict >= 0)
169 st->verdict = chain_offsets
170 [st->verdict + NF_BR_NUMHOOKS];
172 p += e->t->target_size +
173 sizeof(struct ebt_entry_target);
174 tmp->next_offset = p - base;
175 e = e->next;
179 /* Sanity check */
180 if (p - (char *)new->entries != new->entries_size)
181 ebt_print_bug("Entries_size bug");
182 free(chain_offsets);
183 return new;
186 static void store_table_in_file(char *filename, struct ebt_replace *repl)
188 char *data;
189 int size;
190 int fd;
192 /* Start from an empty file with right priviliges */
193 if (!(fd = creat(filename, 0600))) {
194 ebt_print_error("Couldn't create file %s", filename);
195 return;
198 size = sizeof(struct ebt_replace) + repl->entries_size +
199 repl->nentries * sizeof(struct ebt_counter);
200 data = (char *)malloc(size);
201 if (!data)
202 ebt_print_memory();
203 memcpy(data, repl, sizeof(struct ebt_replace));
204 memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries,
205 repl->entries_size);
206 /* Initialize counters to zero, deliver_counters() can update them */
207 memset(data + sizeof(struct ebt_replace) + repl->entries_size,
208 0, repl->nentries * sizeof(struct ebt_counter));
209 if (write(fd, data, size) != size)
210 ebt_print_error("Couldn't write everything to file %s",
211 filename);
212 close(fd);
213 free(data);
216 void ebt_deliver_table(struct ebt_u_replace *u_repl)
218 socklen_t optlen;
219 struct ebt_replace *repl;
221 /* Translate the struct ebt_u_replace to a struct ebt_replace */
222 repl = translate_user2kernel(u_repl);
223 if (u_repl->filename != NULL) {
224 store_table_in_file(u_repl->filename, repl);
225 goto free_repl;
227 /* Give the data to the kernel */
228 optlen = sizeof(struct ebt_replace) + repl->entries_size;
229 if (get_sockfd())
230 goto free_repl;
231 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
232 goto free_repl;
233 if (u_repl->command == 8) { /* The ebtables module may not
234 * yet be loaded with --atomic-commit */
235 ebtables_insmod("ebtables");
236 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES,
237 repl, optlen))
238 goto free_repl;
241 ebt_print_error("The kernel doesn't support a certain ebtables"
242 " extension, consider recompiling your kernel or insmod"
243 " the extension");
244 free_repl:
245 if (repl) {
246 free(repl->entries);
247 free(repl);
251 static int store_counters_in_file(char *filename, struct ebt_u_replace *repl)
253 int size = repl->nentries * sizeof(struct ebt_counter), ret = 0;
254 unsigned int entries_size;
255 struct ebt_replace hlp;
256 FILE *file;
258 if (!(file = fopen(filename, "r+b"))) {
259 ebt_print_error("Could not open file %s", filename);
260 return -1;
262 /* Find out entries_size and then set the file pointer to the
263 * counters */
264 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
265 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
266 sizeof(unsigned int) ||
267 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
268 ebt_print_error("File %s is corrupt", filename);
269 ret = -1;
270 goto close_file;
272 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
273 ebt_print_error("Could not write everything to file %s",
274 filename);
275 ret = -1;
277 close_file:
278 fclose(file);
279 return 0;
282 /* Gets executed after ebt_deliver_table. Delivers the counters to the kernel
283 * and resets the counterchanges to CNT_NORM */
284 void ebt_deliver_counters(struct ebt_u_replace *u_repl)
286 struct ebt_counter *old, *new, *newcounters;
287 socklen_t optlen;
288 struct ebt_replace repl;
289 struct ebt_cntchanges *cc = u_repl->cc->next, *cc2;
290 struct ebt_u_entries *entries;
291 struct ebt_u_entry *next = NULL;
292 int i, chainnr = 0;
294 if (u_repl->nentries == 0)
295 return;
297 newcounters = (struct ebt_counter *)
298 malloc(u_repl->nentries * sizeof(struct ebt_counter));
299 if (!newcounters)
300 ebt_print_memory();
301 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
302 old = u_repl->counters;
303 new = newcounters;
304 while (cc != u_repl->cc) {
305 if (!next || next == entries->entries) {
306 while (chainnr < u_repl->num_chains && (!(entries = u_repl->chains[chainnr++]) ||
307 (next = entries->entries->next) == entries->entries));
308 if (chainnr == u_repl->num_chains)
309 break;
311 if (cc->type == CNT_NORM) {
312 /* 'Normal' rule, meaning we didn't do anything to it
313 * So, we just copy */
314 *new = *old;
315 next->cnt = *new;
316 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
317 old++; /* We've used an old counter */
318 new++; /* We've set a new counter */
319 next = next->next;
320 } else if (cc->type == CNT_DEL) {
321 old++; /* Don't use this old counter */
322 } else {
323 if (cc->type == CNT_CHANGE) {
324 if (cc->change % 3 == 1)
325 new->pcnt = old->pcnt + next->cnt_surplus.pcnt;
326 else if (cc->change % 3 == 2)
327 new->pcnt = old->pcnt - next->cnt_surplus.pcnt;
328 else
329 new->pcnt = next->cnt.pcnt;
330 if (cc->change / 3 == 1)
331 new->bcnt = old->bcnt + next->cnt_surplus.bcnt;
332 else if (cc->change / 3 == 2)
333 new->bcnt = old->bcnt - next->cnt_surplus.bcnt;
334 else
335 new->bcnt = next->cnt.bcnt;
336 } else
337 *new = next->cnt;
338 next->cnt = *new;
339 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
340 if (cc->type == CNT_ADD)
341 new++;
342 else {
343 old++;
344 new++;
346 next = next->next;
348 cc = cc->next;
351 free(u_repl->counters);
352 u_repl->counters = newcounters;
353 u_repl->num_counters = u_repl->nentries;
354 /* Reset the counterchanges to CNT_NORM and delete the unused cc */
355 i = 0;
356 cc = u_repl->cc->next;
357 while (cc != u_repl->cc) {
358 if (cc->type == CNT_DEL) {
359 cc->prev->next = cc->next;
360 cc->next->prev = cc->prev;
361 cc2 = cc->next;
362 free(cc);
363 cc = cc2;
364 } else {
365 cc->type = CNT_NORM;
366 cc->change = 0;
367 i++;
368 cc = cc->next;
371 if (i != u_repl->nentries)
372 ebt_print_bug("i != u_repl->nentries");
373 if (u_repl->filename != NULL) {
374 store_counters_in_file(u_repl->filename, u_repl);
375 return;
377 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
378 sizeof(struct ebt_replace);
379 /* Now put the stuff in the kernel's struct ebt_replace */
380 repl.counters = sparc_cast u_repl->counters;
381 repl.num_counters = u_repl->num_counters;
382 memcpy(repl.name, u_repl->name, sizeof(repl.name));
384 if (get_sockfd())
385 return;
386 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
387 ebt_print_bug("Couldn't update kernel counters");
390 static int
391 ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
393 struct ebt_u_match_list *new;
394 int ret = 0;
396 new = (struct ebt_u_match_list *)
397 malloc(sizeof(struct ebt_u_match_list));
398 if (!new)
399 ebt_print_memory();
400 new->m = (struct ebt_entry_match *)
401 malloc(m->match_size + sizeof(struct ebt_entry_match));
402 if (!new->m)
403 ebt_print_memory();
404 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
405 new->next = NULL;
406 **l = new;
407 *l = &new->next;
408 if (ebt_find_match(new->m->u.name) == NULL) {
409 ebt_print_error("Kernel match %s unsupported by userspace tool",
410 new->m->u.name);
411 ret = -1;
413 return ret;
416 static int
417 ebt_translate_watcher(struct ebt_entry_watcher *w,
418 struct ebt_u_watcher_list ***l)
420 struct ebt_u_watcher_list *new;
421 int ret = 0;
423 new = (struct ebt_u_watcher_list *)
424 malloc(sizeof(struct ebt_u_watcher_list));
425 if (!new)
426 ebt_print_memory();
427 new->w = (struct ebt_entry_watcher *)
428 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
429 if (!new->w)
430 ebt_print_memory();
431 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
432 new->next = NULL;
433 **l = new;
434 *l = &new->next;
435 if (ebt_find_watcher(new->w->u.name) == NULL) {
436 ebt_print_error("Kernel watcher %s unsupported by userspace "
437 "tool", new->w->u.name);
438 ret = -1;
440 return ret;
443 static int
444 ebt_translate_entry(struct ebt_entry *e, int *hook, int *n, int *cnt,
445 int *totalcnt, struct ebt_u_entry **u_e, struct ebt_u_replace *u_repl,
446 unsigned int valid_hooks, char *base, struct ebt_cntchanges **cc)
448 /* An entry */
449 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
450 struct ebt_u_entry *new;
451 struct ebt_u_match_list **m_l;
452 struct ebt_u_watcher_list **w_l;
453 struct ebt_entry_target *t;
455 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
456 if (!new)
457 ebt_print_memory();
458 new->bitmask = e->bitmask;
460 * Plain userspace code doesn't know about
461 * EBT_ENTRY_OR_ENTRIES
463 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
464 new->invflags = e->invflags;
465 new->ethproto = e->ethproto;
466 strcpy(new->in, e->in);
467 strcpy(new->out, e->out);
468 strcpy(new->logical_in, e->logical_in);
469 strcpy(new->logical_out, e->logical_out);
470 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
471 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
472 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
473 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
474 if (*totalcnt >= u_repl->nentries)
475 ebt_print_bug("*totalcnt >= u_repl->nentries");
476 new->cnt = u_repl->counters[*totalcnt];
477 new->cnt_surplus.pcnt = new->cnt_surplus.bcnt = 0;
478 new->cc = *cc;
479 *cc = (*cc)->next;
480 new->m_list = NULL;
481 new->w_list = NULL;
482 new->next = (*u_e)->next;
483 new->next->prev = new;
484 (*u_e)->next = new;
485 new->prev = *u_e;
486 *u_e = new;
487 m_l = &new->m_list;
488 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
489 w_l = &new->w_list;
490 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
492 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
493 new->t = (struct ebt_entry_target *)
494 malloc(t->target_size + sizeof(struct ebt_entry_target));
495 if (!new->t)
496 ebt_print_memory();
497 if (ebt_find_target(t->u.name) == NULL) {
498 ebt_print_error("Kernel target %s unsupported by "
499 "userspace tool", t->u.name);
500 return -1;
502 memcpy(new->t, t, t->target_size +
503 sizeof(struct ebt_entry_target));
504 /* Deal with jumps to udc */
505 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
506 char *tmp = base;
507 int verdict = ((struct ebt_standard_target *)t)->verdict;
508 int i;
510 if (verdict >= 0) {
511 tmp += verdict;
512 for (i = NF_BR_NUMHOOKS; i < u_repl->num_chains; i++)
513 if (u_repl->chains[i]->kernel_start == tmp)
514 break;
515 if (i == u_repl->num_chains)
516 ebt_print_bug("Can't find udc for jump");
517 ((struct ebt_standard_target *)new->t)->verdict = i-NF_BR_NUMHOOKS;
521 (*cnt)++;
522 (*totalcnt)++;
523 return 0;
524 } else { /* A new chain */
525 int i;
526 struct ebt_entries *entries = (struct ebt_entries *)e;
528 if (*n != *cnt)
529 ebt_print_bug("Nr of entries in the chain is wrong");
530 *n = entries->nentries;
531 *cnt = 0;
532 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
533 if (valid_hooks & (1 << i))
534 break;
535 *hook = i;
536 *u_e = u_repl->chains[*hook]->entries;
537 return 0;
541 /* Initialize all chain headers */
542 static int
543 ebt_translate_chains(struct ebt_entry *e, int *hook,
544 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
546 int i;
547 struct ebt_entries *entries = (struct ebt_entries *)e;
548 struct ebt_u_entries *new;
550 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
551 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
552 if (valid_hooks & (1 << i))
553 break;
554 new = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries));
555 if (!new)
556 ebt_print_memory();
557 if (i == u_repl->max_chains)
558 ebt_double_chains(u_repl);
559 u_repl->chains[i] = new;
560 if (i >= NF_BR_NUMHOOKS)
561 new->kernel_start = (char *)e;
562 *hook = i;
563 new->nentries = entries->nentries;
564 new->policy = entries->policy;
565 new->entries = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
566 if (!new->entries)
567 ebt_print_memory();
568 new->entries->next = new->entries->prev = new->entries;
569 new->counter_offset = entries->counter_offset;
570 strcpy(new->name, entries->name);
572 return 0;
575 static int retrieve_from_file(char *filename, struct ebt_replace *repl,
576 char command)
578 FILE *file;
579 char *hlp = NULL, *entries;
580 struct ebt_counter *counters;
581 int size, ret = 0;
583 if (!(file = fopen(filename, "r+b"))) {
584 ebt_print_error("Could not open file %s", filename);
585 return -1;
587 /* Make sure table name is right if command isn't -L or --atomic-commit */
588 if (command != 'L' && command != 8) {
589 hlp = (char *)malloc(strlen(repl->name) + 1);
590 if (!hlp)
591 ebt_print_memory();
592 strcpy(hlp, repl->name);
594 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
595 != sizeof(struct ebt_replace)) {
596 ebt_print_error("File %s is corrupt", filename);
597 ret = -1;
598 goto close_file;
600 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
601 ebt_print_error("File %s contains wrong table name or is "
602 "corrupt", filename);
603 ret = -1;
604 goto close_file;
605 } else if (!ebt_find_table(repl->name)) {
606 ebt_print_error("File %s contains invalid table name",
607 filename);
608 ret = -1;
609 goto close_file;
612 size = sizeof(struct ebt_replace) +
613 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
614 fseek(file, 0, SEEK_END);
615 if (size != ftell(file)) {
616 ebt_print_error("File %s has wrong size", filename);
617 ret = -1;
618 goto close_file;
620 entries = (char *)malloc(repl->entries_size);
621 if (!entries)
622 ebt_print_memory();
623 repl->entries = sparc_cast entries;
624 if (repl->nentries) {
625 counters = (struct ebt_counter *)
626 malloc(repl->nentries * sizeof(struct ebt_counter));
627 repl->counters = sparc_cast counters;
628 if (!repl->counters)
629 ebt_print_memory();
630 } else
631 repl->counters = sparc_cast NULL;
632 /* Copy entries and counters */
633 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
634 fread((char *)repl->entries, sizeof(char), repl->entries_size, file)
635 != repl->entries_size ||
636 fseek(file, sizeof(struct ebt_replace) + repl->entries_size,
637 SEEK_SET)
638 || fread((char *)repl->counters, sizeof(char),
639 repl->nentries * sizeof(struct ebt_counter), file)
640 != repl->nentries * sizeof(struct ebt_counter)) {
641 ebt_print_error("File %s is corrupt", filename);
642 free(entries);
643 repl->entries = NULL;
644 ret = -1;
646 close_file:
647 fclose(file);
648 free(hlp);
649 return ret;
652 static int retrieve_from_kernel(struct ebt_replace *repl, char command,
653 int init)
655 socklen_t optlen;
656 int optname;
657 char *entries;
659 optlen = sizeof(struct ebt_replace);
660 if (get_sockfd())
661 return -1;
662 /* --atomic-init || --init-table */
663 if (init)
664 optname = EBT_SO_GET_INIT_INFO;
665 else
666 optname = EBT_SO_GET_INFO;
667 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
668 return -1;
670 if ( !(entries = (char *)malloc(repl->entries_size)) )
671 ebt_print_memory();
672 repl->entries = sparc_cast entries;
673 if (repl->nentries) {
674 struct ebt_counter *counters;
676 if (!(counters = (struct ebt_counter *)
677 malloc(repl->nentries * sizeof(struct ebt_counter))) )
678 ebt_print_memory();
679 repl->counters = sparc_cast counters;
681 else
682 repl->counters = sparc_cast NULL;
684 /* We want to receive the counters */
685 repl->num_counters = repl->nentries;
686 optlen += repl->entries_size + repl->num_counters *
687 sizeof(struct ebt_counter);
688 if (init)
689 optname = EBT_SO_GET_INIT_ENTRIES;
690 else
691 optname = EBT_SO_GET_ENTRIES;
692 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
693 ebt_print_bug("Hmm, what is wrong??? bug#1");
695 return 0;
698 int ebt_get_table(struct ebt_u_replace *u_repl, int init)
700 int i, j, k, hook;
701 struct ebt_replace repl;
702 struct ebt_u_entry *u_e;
703 struct ebt_cntchanges *new_cc, *cc;
705 strcpy(repl.name, u_repl->name);
706 if (u_repl->filename != NULL) {
707 if (init)
708 ebt_print_bug("Getting initial table data from a file is impossible");
709 if (retrieve_from_file(u_repl->filename, &repl, u_repl->command))
710 return -1;
711 /* -L with a wrong table name should be dealt with silently */
712 strcpy(u_repl->name, repl.name);
713 } else if (retrieve_from_kernel(&repl, u_repl->command, init))
714 return -1;
716 /* Translate the struct ebt_replace to a struct ebt_u_replace */
717 u_repl->valid_hooks = repl.valid_hooks;
718 u_repl->nentries = repl.nentries;
719 u_repl->num_counters = repl.num_counters;
720 u_repl->counters = repl.counters;
721 u_repl->cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
722 if (!u_repl->cc)
723 ebt_print_memory();
724 u_repl->cc->next = u_repl->cc->prev = u_repl->cc;
725 cc = u_repl->cc;
726 for (i = 0; i < repl.nentries; i++) {
727 new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
728 if (!new_cc)
729 ebt_print_memory();
730 new_cc->type = CNT_NORM;
731 new_cc->change = 0;
732 new_cc->prev = cc;
733 cc->next = new_cc;
734 cc = new_cc;
736 if (repl.nentries) {
737 new_cc->next = u_repl->cc;
738 u_repl->cc->prev = new_cc;
740 u_repl->chains = (struct ebt_u_entries **)calloc(EBT_ORI_MAX_CHAINS, sizeof(void *));
741 u_repl->max_chains = EBT_ORI_MAX_CHAINS;
742 hook = -1;
743 /* FIXME: Clean up when an error is encountered */
744 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
745 &hook, u_repl, u_repl->valid_hooks);
746 if (hook >= NF_BR_NUMHOOKS)
747 u_repl->num_chains = hook + 1;
748 else
749 u_repl->num_chains = NF_BR_NUMHOOKS;
750 i = 0; /* Holds the expected nr. of entries for the chain */
751 j = 0; /* Holds the up to now counted entries for the chain */
752 k = 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */
753 cc = u_repl->cc->next;
754 hook = -1;
755 EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size,
756 ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl,
757 u_repl->valid_hooks, (char *)repl.entries, &cc);
758 if (k != u_repl->nentries)
759 ebt_print_bug("Wrong total nentries");
760 free(repl.entries);
761 return 0;