usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / ebtables / communication.c
blob0917f6e153e93b4b8fcba44bf236fc3d577593a7
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 *)calloc(u_repl->num_chains, sizeof(unsigned int));
70 if (!chain_offsets)
71 ebt_print_memory();
72 /* Determine size */
73 for (i = 0; i < u_repl->num_chains; i++) {
74 if (!(entries = u_repl->chains[i]))
75 continue;
76 chain_offsets[i] = entries_size;
77 entries_size += sizeof(struct ebt_entries);
78 j = 0;
79 e = entries->entries->next;
80 while (e != entries->entries) {
81 j++;
82 entries_size += sizeof(struct ebt_entry);
83 m_l = e->m_list;
84 while (m_l) {
85 entries_size += m_l->m->match_size +
86 sizeof(struct ebt_entry_match);
87 m_l = m_l->next;
89 w_l = e->w_list;
90 while (w_l) {
91 entries_size += w_l->w->watcher_size +
92 sizeof(struct ebt_entry_watcher);
93 w_l = w_l->next;
95 entries_size += e->t->target_size +
96 sizeof(struct ebt_entry_target);
97 e = e->next;
99 /* A little sanity check */
100 if (j != entries->nentries)
101 ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j,
102 entries->nentries, entries->name);
105 new->entries_size = entries_size;
106 p = (char *)malloc(entries_size);
107 if (!p)
108 ebt_print_memory();
110 /* Put everything in one block */
111 new->entries = sparc_cast p;
112 for (i = 0; i < u_repl->num_chains; i++) {
113 struct ebt_entries *hlp;
115 hlp = (struct ebt_entries *)p;
116 if (!(entries = u_repl->chains[i]))
117 continue;
118 if (i < NF_BR_NUMHOOKS)
119 new->hook_entry[i] = sparc_cast hlp;
120 hlp->nentries = entries->nentries;
121 hlp->policy = entries->policy;
122 strcpy(hlp->name, entries->name);
123 hlp->counter_offset = entries->counter_offset;
124 hlp->distinguisher = 0; /* Make the kernel see the light */
125 p += sizeof(struct ebt_entries);
126 e = entries->entries->next;
127 while (e != entries->entries) {
128 struct ebt_entry *tmp = (struct ebt_entry *)p;
130 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
131 tmp->invflags = e->invflags;
132 tmp->ethproto = e->ethproto;
133 strcpy(tmp->in, e->in);
134 strcpy(tmp->out, e->out);
135 strcpy(tmp->logical_in, e->logical_in);
136 strcpy(tmp->logical_out, e->logical_out);
137 memcpy(tmp->sourcemac, e->sourcemac,
138 sizeof(tmp->sourcemac));
139 memcpy(tmp->sourcemsk, e->sourcemsk,
140 sizeof(tmp->sourcemsk));
141 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
142 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
144 base = p;
145 p += sizeof(struct ebt_entry);
146 m_l = e->m_list;
147 while (m_l) {
148 memcpy(p, m_l->m, m_l->m->match_size +
149 sizeof(struct ebt_entry_match));
150 p += m_l->m->match_size +
151 sizeof(struct ebt_entry_match);
152 m_l = m_l->next;
154 tmp->watchers_offset = p - base;
155 w_l = e->w_list;
156 while (w_l) {
157 memcpy(p, w_l->w, w_l->w->watcher_size +
158 sizeof(struct ebt_entry_watcher));
159 p += w_l->w->watcher_size +
160 sizeof(struct ebt_entry_watcher);
161 w_l = w_l->next;
163 tmp->target_offset = p - base;
164 memcpy(p, e->t, e->t->target_size +
165 sizeof(struct ebt_entry_target));
166 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
167 struct ebt_standard_target *st =
168 (struct ebt_standard_target *)p;
169 /* Translate the jump to a udc */
170 if (st->verdict >= 0)
171 st->verdict = chain_offsets
172 [st->verdict + NF_BR_NUMHOOKS];
174 p += e->t->target_size +
175 sizeof(struct ebt_entry_target);
176 tmp->next_offset = p - base;
177 e = e->next;
181 /* Sanity check */
182 if (p - (char *)new->entries != new->entries_size)
183 ebt_print_bug("Entries_size bug");
184 free(chain_offsets);
185 return new;
188 static void store_table_in_file(char *filename, struct ebt_replace *repl)
190 char *data;
191 int size;
192 int fd;
194 /* Start from an empty file with the correct priviliges */
195 if ((fd = creat(filename, 0600)) == -1) {
196 ebt_print_error("Couldn't create file %s", filename);
197 return;
200 size = sizeof(struct ebt_replace) + repl->entries_size +
201 repl->nentries * sizeof(struct ebt_counter);
202 data = (char *)malloc(size);
203 if (!data)
204 ebt_print_memory();
205 memcpy(data, repl, sizeof(struct ebt_replace));
206 memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries,
207 repl->entries_size);
208 /* Initialize counters to zero, deliver_counters() can update them */
209 memset(data + sizeof(struct ebt_replace) + repl->entries_size,
210 0, repl->nentries * sizeof(struct ebt_counter));
211 if (write(fd, data, size) != size)
212 ebt_print_error("Couldn't write everything to file %s",
213 filename);
214 close(fd);
215 free(data);
218 void ebt_deliver_table(struct ebt_u_replace *u_repl)
220 socklen_t optlen;
221 struct ebt_replace *repl;
223 /* Translate the struct ebt_u_replace to a struct ebt_replace */
224 repl = translate_user2kernel(u_repl);
225 if (u_repl->filename != NULL) {
226 store_table_in_file(u_repl->filename, repl);
227 goto free_repl;
229 /* Give the data to the kernel */
230 optlen = sizeof(struct ebt_replace) + repl->entries_size;
231 if (get_sockfd())
232 goto free_repl;
233 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
234 goto free_repl;
235 if (u_repl->command == 8) { /* The ebtables module may not
236 * yet be loaded with --atomic-commit */
237 ebtables_insmod("ebtables");
238 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES,
239 repl, optlen))
240 goto free_repl;
243 ebt_print_error("Unable to update the kernel. Two possible causes:\n"
244 "1. Multiple ebtables programs were executing simultaneously. The ebtables\n"
245 " userspace tool doesn't by default support multiple ebtables programs running\n"
246 " concurrently. The ebtables option --concurrent or a tool like flock can be\n"
247 " used to support concurrent scripts that update the ebtables kernel tables.\n"
248 "2. The kernel doesn't support a certain ebtables extension, consider\n"
249 " recompiling your kernel or insmod the extension.\n");
250 free_repl:
251 if (repl) {
252 free(repl->entries);
253 free(repl);
257 static int store_counters_in_file(char *filename, struct ebt_u_replace *repl)
259 int size = repl->nentries * sizeof(struct ebt_counter), ret = 0;
260 unsigned int entries_size;
261 struct ebt_replace hlp;
262 FILE *file;
264 if (!(file = fopen(filename, "r+b"))) {
265 ebt_print_error("Could not open file %s", filename);
266 return -1;
268 /* Find out entries_size and then set the file pointer to the
269 * counters */
270 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
271 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
272 sizeof(unsigned int) ||
273 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
274 ebt_print_error("File %s is corrupt", filename);
275 ret = -1;
276 goto close_file;
278 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
279 ebt_print_error("Could not write everything to file %s",
280 filename);
281 ret = -1;
283 close_file:
284 fclose(file);
285 return 0;
288 /* Gets executed after ebt_deliver_table. Delivers the counters to the kernel
289 * and resets the counterchanges to CNT_NORM */
290 void ebt_deliver_counters(struct ebt_u_replace *u_repl)
292 struct ebt_counter *old, *new, *newcounters;
293 socklen_t optlen;
294 struct ebt_replace repl;
295 struct ebt_cntchanges *cc = u_repl->cc->next, *cc2;
296 struct ebt_u_entries *entries = NULL;
297 struct ebt_u_entry *next = NULL;
298 int i, chainnr = 0;
300 if (u_repl->nentries == 0)
301 return;
303 newcounters = (struct ebt_counter *)
304 malloc(u_repl->nentries * sizeof(struct ebt_counter));
305 if (!newcounters)
306 ebt_print_memory();
307 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
308 old = u_repl->counters;
309 new = newcounters;
310 while (cc != u_repl->cc) {
311 if (!next || next == entries->entries) {
312 while (chainnr < u_repl->num_chains && (!(entries = u_repl->chains[chainnr]) ||
313 (next = entries->entries->next) == entries->entries))
314 chainnr++;
315 if (chainnr == u_repl->num_chains)
316 break;
318 if (next == NULL)
319 ebt_print_bug("next == NULL");
320 if (cc->type == CNT_NORM) {
321 /* 'Normal' rule, meaning we didn't do anything to it
322 * So, we just copy */
323 *new = *old;
324 next->cnt = *new;
325 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
326 old++; /* We've used an old counter */
327 new++; /* We've set a new counter */
328 next = next->next;
329 } else if (cc->type == CNT_DEL) {
330 old++; /* Don't use this old counter */
331 } else {
332 if (cc->type == CNT_CHANGE) {
333 if (cc->change % 3 == 1)
334 new->pcnt = old->pcnt + next->cnt_surplus.pcnt;
335 else if (cc->change % 3 == 2)
336 new->pcnt = old->pcnt - next->cnt_surplus.pcnt;
337 else
338 new->pcnt = next->cnt.pcnt;
339 if (cc->change / 3 == 1)
340 new->bcnt = old->bcnt + next->cnt_surplus.bcnt;
341 else if (cc->change / 3 == 2)
342 new->bcnt = old->bcnt - next->cnt_surplus.bcnt;
343 else
344 new->bcnt = next->cnt.bcnt;
345 } else
346 *new = next->cnt;
347 next->cnt = *new;
348 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
349 if (cc->type == CNT_ADD)
350 new++;
351 else {
352 old++;
353 new++;
355 next = next->next;
357 cc = cc->next;
360 free(u_repl->counters);
361 u_repl->counters = newcounters;
362 u_repl->num_counters = u_repl->nentries;
363 /* Reset the counterchanges to CNT_NORM and delete the unused cc */
364 i = 0;
365 cc = u_repl->cc->next;
366 while (cc != u_repl->cc) {
367 if (cc->type == CNT_DEL) {
368 cc->prev->next = cc->next;
369 cc->next->prev = cc->prev;
370 cc2 = cc->next;
371 free(cc);
372 cc = cc2;
373 } else {
374 cc->type = CNT_NORM;
375 cc->change = 0;
376 i++;
377 cc = cc->next;
380 if (i != u_repl->nentries)
381 ebt_print_bug("i != u_repl->nentries");
382 if (u_repl->filename != NULL) {
383 store_counters_in_file(u_repl->filename, u_repl);
384 return;
386 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
387 sizeof(struct ebt_replace);
388 /* Now put the stuff in the kernel's struct ebt_replace */
389 repl.counters = sparc_cast u_repl->counters;
390 repl.num_counters = u_repl->num_counters;
391 memcpy(repl.name, u_repl->name, sizeof(repl.name));
393 if (get_sockfd())
394 return;
395 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
396 ebt_print_bug("Couldn't update kernel counters");
399 static int
400 ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
402 struct ebt_u_match_list *new;
403 int ret = 0;
405 new = (struct ebt_u_match_list *)
406 malloc(sizeof(struct ebt_u_match_list));
407 if (!new)
408 ebt_print_memory();
409 new->m = (struct ebt_entry_match *)
410 malloc(m->match_size + sizeof(struct ebt_entry_match));
411 if (!new->m)
412 ebt_print_memory();
413 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
414 new->next = NULL;
415 **l = new;
416 *l = &new->next;
417 if (ebt_find_match(new->m->u.name) == NULL) {
418 ebt_print_error("Kernel match %s unsupported by userspace tool",
419 new->m->u.name);
420 ret = -1;
422 return ret;
425 static int
426 ebt_translate_watcher(struct ebt_entry_watcher *w,
427 struct ebt_u_watcher_list ***l)
429 struct ebt_u_watcher_list *new;
430 int ret = 0;
432 new = (struct ebt_u_watcher_list *)
433 malloc(sizeof(struct ebt_u_watcher_list));
434 if (!new)
435 ebt_print_memory();
436 new->w = (struct ebt_entry_watcher *)
437 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
438 if (!new->w)
439 ebt_print_memory();
440 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
441 new->next = NULL;
442 **l = new;
443 *l = &new->next;
444 if (ebt_find_watcher(new->w->u.name) == NULL) {
445 ebt_print_error("Kernel watcher %s unsupported by userspace "
446 "tool", new->w->u.name);
447 ret = -1;
449 return ret;
452 static int
453 ebt_translate_entry(struct ebt_entry *e, int *hook, int *n, int *cnt,
454 int *totalcnt, struct ebt_u_entry **u_e, struct ebt_u_replace *u_repl,
455 unsigned int valid_hooks, char *base, struct ebt_cntchanges **cc)
457 /* An entry */
458 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
459 struct ebt_u_entry *new;
460 struct ebt_u_match_list **m_l;
461 struct ebt_u_watcher_list **w_l;
462 struct ebt_entry_target *t;
464 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
465 if (!new)
466 ebt_print_memory();
467 new->bitmask = e->bitmask;
469 * Plain userspace code doesn't know about
470 * EBT_ENTRY_OR_ENTRIES
472 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
473 new->invflags = e->invflags;
474 new->ethproto = e->ethproto;
475 strcpy(new->in, e->in);
476 strcpy(new->out, e->out);
477 strcpy(new->logical_in, e->logical_in);
478 strcpy(new->logical_out, e->logical_out);
479 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
480 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
481 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
482 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
483 if (*totalcnt >= u_repl->nentries)
484 ebt_print_bug("*totalcnt >= u_repl->nentries");
485 new->cnt = u_repl->counters[*totalcnt];
486 new->cnt_surplus.pcnt = new->cnt_surplus.bcnt = 0;
487 new->cc = *cc;
488 *cc = (*cc)->next;
489 new->m_list = NULL;
490 new->w_list = NULL;
491 new->next = (*u_e)->next;
492 new->next->prev = new;
493 (*u_e)->next = new;
494 new->prev = *u_e;
495 *u_e = new;
496 m_l = &new->m_list;
497 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
498 w_l = &new->w_list;
499 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
501 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
502 new->t = (struct ebt_entry_target *)
503 malloc(t->target_size + sizeof(struct ebt_entry_target));
504 if (!new->t)
505 ebt_print_memory();
506 if (ebt_find_target(t->u.name) == NULL) {
507 ebt_print_error("Kernel target %s unsupported by "
508 "userspace tool", t->u.name);
509 return -1;
511 memcpy(new->t, t, t->target_size +
512 sizeof(struct ebt_entry_target));
513 /* Deal with jumps to udc */
514 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
515 char *tmp = base;
516 int verdict = ((struct ebt_standard_target *)t)->verdict;
517 int i;
519 if (verdict >= 0) {
520 tmp += verdict;
521 for (i = NF_BR_NUMHOOKS; i < u_repl->num_chains; i++)
522 if (u_repl->chains[i]->kernel_start == tmp)
523 break;
524 if (i == u_repl->num_chains)
525 ebt_print_bug("Can't find udc for jump");
526 ((struct ebt_standard_target *)new->t)->verdict = i-NF_BR_NUMHOOKS;
530 (*cnt)++;
531 (*totalcnt)++;
532 return 0;
533 } else { /* A new chain */
534 int i;
535 struct ebt_entries *entries = (struct ebt_entries *)e;
537 if (*n != *cnt)
538 ebt_print_bug("Nr of entries in the chain is wrong");
539 *n = entries->nentries;
540 *cnt = 0;
541 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
542 if (valid_hooks & (1 << i))
543 break;
544 *hook = i;
545 *u_e = u_repl->chains[*hook]->entries;
546 return 0;
550 /* Initialize all chain headers */
551 static int
552 ebt_translate_chains(struct ebt_entry *e, int *hook,
553 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
555 int i;
556 struct ebt_entries *entries = (struct ebt_entries *)e;
557 struct ebt_u_entries *new;
559 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
560 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
561 if (valid_hooks & (1 << i))
562 break;
563 new = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries));
564 if (!new)
565 ebt_print_memory();
566 if (i == u_repl->max_chains)
567 ebt_double_chains(u_repl);
568 u_repl->chains[i] = new;
569 if (i >= NF_BR_NUMHOOKS)
570 new->kernel_start = (char *)e;
571 *hook = i;
572 new->nentries = entries->nentries;
573 new->policy = entries->policy;
574 new->entries = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
575 if (!new->entries)
576 ebt_print_memory();
577 new->entries->next = new->entries->prev = new->entries;
578 new->counter_offset = entries->counter_offset;
579 strcpy(new->name, entries->name);
581 return 0;
584 static int retrieve_from_file(char *filename, struct ebt_replace *repl,
585 char command)
587 FILE *file;
588 char *hlp = NULL, *entries;
589 struct ebt_counter *counters;
590 int size, ret = 0;
592 if (!(file = fopen(filename, "r+b"))) {
593 ebt_print_error("Could not open file %s", filename);
594 return -1;
596 /* Make sure table name is right if command isn't -L or --atomic-commit */
597 if (command != 'L' && command != 8) {
598 hlp = (char *)malloc(strlen(repl->name) + 1);
599 if (!hlp)
600 ebt_print_memory();
601 strcpy(hlp, repl->name);
603 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
604 != sizeof(struct ebt_replace)) {
605 ebt_print_error("File %s is corrupt", filename);
606 ret = -1;
607 goto close_file;
609 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
610 ebt_print_error("File %s contains wrong table name or is "
611 "corrupt", filename);
612 ret = -1;
613 goto close_file;
614 } else if (!ebt_find_table(repl->name)) {
615 ebt_print_error("File %s contains invalid table name",
616 filename);
617 ret = -1;
618 goto close_file;
621 size = sizeof(struct ebt_replace) +
622 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
623 fseek(file, 0, SEEK_END);
624 if (size != ftell(file)) {
625 ebt_print_error("File %s has wrong size", filename);
626 ret = -1;
627 goto close_file;
629 entries = (char *)malloc(repl->entries_size);
630 if (!entries)
631 ebt_print_memory();
632 repl->entries = sparc_cast entries;
633 if (repl->nentries) {
634 counters = (struct ebt_counter *)
635 malloc(repl->nentries * sizeof(struct ebt_counter));
636 repl->counters = sparc_cast counters;
637 if (!repl->counters)
638 ebt_print_memory();
639 } else
640 repl->counters = sparc_cast NULL;
641 /* Copy entries and counters */
642 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
643 fread((char *)repl->entries, sizeof(char), repl->entries_size, file)
644 != repl->entries_size ||
645 fseek(file, sizeof(struct ebt_replace) + repl->entries_size,
646 SEEK_SET)
647 || (repl->counters && fread((char *)repl->counters, sizeof(char),
648 repl->nentries * sizeof(struct ebt_counter), file)
649 != repl->nentries * sizeof(struct ebt_counter))) {
650 ebt_print_error("File %s is corrupt", filename);
651 free(entries);
652 repl->entries = NULL;
653 ret = -1;
655 close_file:
656 fclose(file);
657 free(hlp);
658 return ret;
661 static int retrieve_from_kernel(struct ebt_replace *repl, char command,
662 int init)
664 socklen_t optlen;
665 int optname;
666 char *entries;
668 optlen = sizeof(struct ebt_replace);
669 if (get_sockfd())
670 return -1;
671 /* --atomic-init || --init-table */
672 if (init)
673 optname = EBT_SO_GET_INIT_INFO;
674 else
675 optname = EBT_SO_GET_INFO;
676 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
677 return -1;
679 if ( !(entries = (char *)malloc(repl->entries_size)) )
680 ebt_print_memory();
681 repl->entries = sparc_cast entries;
682 if (repl->nentries) {
683 struct ebt_counter *counters;
685 if (!(counters = (struct ebt_counter *)
686 malloc(repl->nentries * sizeof(struct ebt_counter))) )
687 ebt_print_memory();
688 repl->counters = sparc_cast counters;
690 else
691 repl->counters = sparc_cast NULL;
693 /* We want to receive the counters */
694 repl->num_counters = repl->nentries;
695 optlen += repl->entries_size + repl->num_counters *
696 sizeof(struct ebt_counter);
697 if (init)
698 optname = EBT_SO_GET_INIT_ENTRIES;
699 else
700 optname = EBT_SO_GET_ENTRIES;
701 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
702 ebt_print_bug("Hmm, what is wrong??? bug#1");
704 return 0;
707 int ebt_get_table(struct ebt_u_replace *u_repl, int init)
709 int i, j, k, hook;
710 struct ebt_replace repl;
711 struct ebt_u_entry *u_e = NULL;
712 struct ebt_cntchanges *new_cc = NULL, *cc;
714 strcpy(repl.name, u_repl->name);
715 if (u_repl->filename != NULL) {
716 if (init)
717 ebt_print_bug("Getting initial table data from a file is impossible");
718 if (retrieve_from_file(u_repl->filename, &repl, u_repl->command))
719 return -1;
720 /* -L with a wrong table name should be dealt with silently */
721 strcpy(u_repl->name, repl.name);
722 } else if (retrieve_from_kernel(&repl, u_repl->command, init))
723 return -1;
725 /* Translate the struct ebt_replace to a struct ebt_u_replace */
726 u_repl->valid_hooks = repl.valid_hooks;
727 u_repl->nentries = repl.nentries;
728 u_repl->num_counters = repl.num_counters;
729 u_repl->counters = repl.counters;
730 u_repl->cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
731 if (!u_repl->cc)
732 ebt_print_memory();
733 u_repl->cc->next = u_repl->cc->prev = u_repl->cc;
734 cc = u_repl->cc;
735 for (i = 0; i < repl.nentries; i++) {
736 new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
737 if (!new_cc)
738 ebt_print_memory();
739 new_cc->type = CNT_NORM;
740 new_cc->change = 0;
741 new_cc->prev = cc;
742 cc->next = new_cc;
743 cc = new_cc;
745 if (repl.nentries) {
746 new_cc->next = u_repl->cc;
747 u_repl->cc->prev = new_cc;
749 u_repl->chains = (struct ebt_u_entries **)calloc(EBT_ORI_MAX_CHAINS, sizeof(void *));
750 u_repl->max_chains = EBT_ORI_MAX_CHAINS;
751 hook = -1;
752 /* FIXME: Clean up when an error is encountered */
753 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
754 &hook, u_repl, u_repl->valid_hooks);
755 if (hook >= NF_BR_NUMHOOKS)
756 u_repl->num_chains = hook + 1;
757 else
758 u_repl->num_chains = NF_BR_NUMHOOKS;
759 i = 0; /* Holds the expected nr. of entries for the chain */
760 j = 0; /* Holds the up to now counted entries for the chain */
761 k = 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */
762 cc = u_repl->cc->next;
763 hook = -1;
764 EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size,
765 ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl,
766 u_repl->valid_hooks, (char *)repl.entries, &cc);
767 if (k != u_repl->nentries)
768 ebt_print_bug("Wrong total nentries");
769 free(repl.entries);
770 return 0;