Don't use 'release' macro.
[platform/upstream/ebtables.git] / communication.c
1 /*
2  * communication.c, v2.0 July 2002
3  *
4  * Author: Bart De Schuymer
5  *
6  */
7
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.
13  */
14
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"
24
25 extern char* hooknames[NF_BR_NUMHOOKS];
26
27 #ifdef KERNEL_64_USERSPACE_32
28 #define sparc_cast (uint64_t)
29 #else
30 #define sparc_cast
31 #endif
32
33 int sockfd = -1;
34
35 static int get_sockfd()
36 {
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;
45                 }
46         }
47         return ret;
48 }
49
50 static struct ebt_replace *translate_user2kernel(struct ebt_u_replace *u_repl)
51 {
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;
60
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;
88                         }
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;
94                         }
95                         entries_size += e->t->target_size +
96                            sizeof(struct ebt_entry_target);
97                         e = e->next;
98                 }
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);
103         }
104
105         new->entries_size = entries_size;
106         p = (char *)malloc(entries_size);
107         if (!p)
108                 ebt_print_memory();
109
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;
114
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;
129
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));
143
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;
153                         }
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;
162                         }
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];
173                         }
174                         p += e->t->target_size +
175                            sizeof(struct ebt_entry_target);
176                         tmp->next_offset = p - base;
177                         e = e->next;
178                 }
179         }
180
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;
186 }
187
188 static void store_table_in_file(char *filename, struct ebt_replace *repl)
189 {
190         char *data;
191         int size;
192         int fd;
193
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;
198         }
199
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);
216 }
217
218 void ebt_deliver_table(struct ebt_u_replace *u_repl)
219 {
220         socklen_t optlen;
221         struct ebt_replace *repl;
222
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;
228         }
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;
241         }
242
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);
254         }
255 }
256
257 static int store_counters_in_file(char *filename, struct ebt_u_replace *repl)
258 {
259         int size = repl->nentries * sizeof(struct ebt_counter), ret = 0;
260         unsigned int entries_size;
261         struct ebt_replace hlp;
262         FILE *file;
263
264         if (!(file = fopen(filename, "r+b"))) {
265                 ebt_print_error("Could not open file %s", filename);
266                 return -1;
267         }
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;
277         }
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;
282         }
283 close_file:
284         fclose(file);
285         return ret;
286 }
287
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)
291 {
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 = -1;
299
300         if (u_repl->nentries == 0)
301                 return;
302
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                         chainnr++;
313                         while (chainnr < u_repl->num_chains && (!(entries = u_repl->chains[chainnr]) ||
314                                (next = entries->entries->next) == entries->entries))
315                                 chainnr++;
316                         if (chainnr == u_repl->num_chains)
317                                 break;
318                 }
319                 if (next == NULL)
320                         ebt_print_bug("next == NULL");
321                 if (cc->type == CNT_NORM) {
322                         /* 'Normal' rule, meaning we didn't do anything to it
323                          * So, we just copy */
324                         *new = *old;
325                         next->cnt = *new;
326                         next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
327                         old++; /* We've used an old counter */
328                         new++; /* We've set a new counter */
329                         next = next->next;
330                 } else if (cc->type == CNT_DEL) {
331                         old++; /* Don't use this old counter */
332                 } else {
333                         if (cc->type == CNT_CHANGE) {
334                                 if (cc->change % 3 == 1)
335                                         new->pcnt = old->pcnt + next->cnt_surplus.pcnt;
336                                 else if (cc->change % 3 == 2)
337                                         new->pcnt = old->pcnt - next->cnt_surplus.pcnt;
338                                 else
339                                         new->pcnt = next->cnt.pcnt;
340                                 if (cc->change / 3 == 1)
341                                         new->bcnt = old->bcnt + next->cnt_surplus.bcnt;
342                                 else if (cc->change / 3 == 2)
343                                         new->bcnt = old->bcnt - next->cnt_surplus.bcnt;
344                                 else
345                                         new->bcnt = next->cnt.bcnt;
346                         } else
347                                 *new = next->cnt;
348                         next->cnt = *new;
349                         next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
350                         if (cc->type == CNT_ADD)
351                                 new++;
352                         else {
353                                 old++;
354                                 new++;
355                         }
356                         next = next->next;
357                 }
358                 cc = cc->next;
359         }
360
361         free(u_repl->counters);
362         u_repl->counters = newcounters;
363         u_repl->num_counters = u_repl->nentries;
364         /* Reset the counterchanges to CNT_NORM and delete the unused cc */
365         i = 0;
366         cc = u_repl->cc->next;
367         while (cc != u_repl->cc) {
368                 if (cc->type == CNT_DEL) {
369                         cc->prev->next = cc->next;
370                         cc->next->prev = cc->prev;
371                         cc2 = cc->next;
372                         free(cc);
373                         cc = cc2;
374                 } else {
375                         cc->type = CNT_NORM;
376                         cc->change = 0;
377                         i++;
378                         cc = cc->next;
379                 }
380         }
381         if (i != u_repl->nentries)
382                 ebt_print_bug("i != u_repl->nentries");
383         if (u_repl->filename != NULL) {
384                 store_counters_in_file(u_repl->filename, u_repl);
385                 return;
386         }
387         optlen = u_repl->nentries * sizeof(struct ebt_counter) +
388            sizeof(struct ebt_replace);
389         /* Now put the stuff in the kernel's struct ebt_replace */
390         repl.counters = sparc_cast u_repl->counters;
391         repl.num_counters = u_repl->num_counters;
392         memcpy(repl.name, u_repl->name, sizeof(repl.name));
393
394         if (get_sockfd())
395                 return;
396         if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
397                 ebt_print_bug("Couldn't update kernel counters");
398 }
399
400 static int
401 ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
402 {
403         struct ebt_u_match_list *new;
404         int ret = 0;
405
406         new = (struct ebt_u_match_list *)
407            malloc(sizeof(struct ebt_u_match_list));
408         if (!new)
409                 ebt_print_memory();
410         new->m = (struct ebt_entry_match *)
411            malloc(m->match_size + sizeof(struct ebt_entry_match));
412         if (!new->m)
413                 ebt_print_memory();
414         memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
415         new->next = NULL;
416         **l = new;
417         *l = &new->next;
418         if (ebt_find_match(new->m->u.name) == NULL) {
419                 ebt_print_error("Kernel match %s unsupported by userspace tool",
420                                 new->m->u.name);
421                 ret = -1;
422         }
423         return ret;
424 }
425
426 static int
427 ebt_translate_watcher(struct ebt_entry_watcher *w,
428    struct ebt_u_watcher_list ***l)
429 {
430         struct ebt_u_watcher_list *new;
431         int ret = 0;
432
433         new = (struct ebt_u_watcher_list *)
434            malloc(sizeof(struct ebt_u_watcher_list));
435         if (!new)
436                 ebt_print_memory();
437         new->w = (struct ebt_entry_watcher *)
438            malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
439         if (!new->w)
440                 ebt_print_memory();
441         memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
442         new->next = NULL;
443         **l = new;
444         *l = &new->next;
445         if (ebt_find_watcher(new->w->u.name) == NULL) {
446                 ebt_print_error("Kernel watcher %s unsupported by userspace "
447                                 "tool", new->w->u.name);
448                 ret = -1;
449         }
450         return ret;
451 }
452
453 static int
454 ebt_translate_entry(struct ebt_entry *e, int *hook, int *n, int *cnt,
455    int *totalcnt, struct ebt_u_entry **u_e, struct ebt_u_replace *u_repl,
456    unsigned int valid_hooks, char *base, struct ebt_cntchanges **cc)
457 {
458         /* An entry */
459         if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
460                 struct ebt_u_entry *new;
461                 struct ebt_u_match_list **m_l;
462                 struct ebt_u_watcher_list **w_l;
463                 struct ebt_entry_target *t;
464
465                 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
466                 if (!new)
467                         ebt_print_memory();
468                 new->bitmask = e->bitmask;
469                 /*
470                  * Plain userspace code doesn't know about
471                  * EBT_ENTRY_OR_ENTRIES
472                  */
473                 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
474                 new->invflags = e->invflags;
475                 new->ethproto = e->ethproto;
476                 strcpy(new->in, e->in);
477                 strcpy(new->out, e->out);
478                 strcpy(new->logical_in, e->logical_in);
479                 strcpy(new->logical_out, e->logical_out);
480                 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
481                 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
482                 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
483                 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
484                 if (*totalcnt >= u_repl->nentries)
485                         ebt_print_bug("*totalcnt >= u_repl->nentries");
486                 new->cnt = u_repl->counters[*totalcnt];
487                 new->cnt_surplus.pcnt = new->cnt_surplus.bcnt = 0;
488                 new->cc = *cc;
489                 *cc = (*cc)->next;
490                 new->m_list = NULL;
491                 new->w_list = NULL;
492                 new->next = (*u_e)->next;
493                 new->next->prev = new;
494                 (*u_e)->next = new;
495                 new->prev = *u_e;
496                 *u_e = new;
497                 m_l = &new->m_list;
498                 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
499                 w_l = &new->w_list;
500                 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
501
502                 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
503                 new->t = (struct ebt_entry_target *)
504                    malloc(t->target_size + sizeof(struct ebt_entry_target));
505                 if (!new->t)
506                         ebt_print_memory();
507                 if (ebt_find_target(t->u.name) == NULL) {
508                         ebt_print_error("Kernel target %s unsupported by "
509                                         "userspace tool", t->u.name);
510                         return -1;
511                 }
512                 memcpy(new->t, t, t->target_size +
513                    sizeof(struct ebt_entry_target));
514                 /* Deal with jumps to udc */
515                 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
516                         char *tmp = base;
517                         int verdict = ((struct ebt_standard_target *)t)->verdict;
518                         int i;
519
520                         if (verdict >= 0) {
521                                 tmp += verdict;
522                                 for (i = NF_BR_NUMHOOKS; i < u_repl->num_chains; i++)
523                                         if (u_repl->chains[i]->kernel_start == tmp)
524                                                 break;
525                                 if (i == u_repl->num_chains)
526                                         ebt_print_bug("Can't find udc for jump");
527                                 ((struct ebt_standard_target *)new->t)->verdict = i-NF_BR_NUMHOOKS;
528                         }
529                 }
530
531                 (*cnt)++;
532                 (*totalcnt)++;
533                 return 0;
534         } else { /* A new chain */
535                 int i;
536                 struct ebt_entries *entries = (struct ebt_entries *)e;
537
538                 if (*n != *cnt)
539                         ebt_print_bug("Nr of entries in the chain is wrong");
540                 *n = entries->nentries;
541                 *cnt = 0;
542                 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
543                         if (valid_hooks & (1 << i))
544                                 break;
545                 *hook = i;
546                 *u_e = u_repl->chains[*hook]->entries;
547                 return 0;
548         }
549 }
550
551 /* Initialize all chain headers */
552 static int
553 ebt_translate_chains(struct ebt_entry *e, int *hook,
554    struct ebt_u_replace *u_repl, unsigned int valid_hooks)
555 {
556         int i;
557         struct ebt_entries *entries = (struct ebt_entries *)e;
558         struct ebt_u_entries *new;
559
560         if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
561                 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
562                         if (valid_hooks & (1 << i))
563                                 break;
564                 new = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries));
565                 if (!new)
566                         ebt_print_memory();
567                 if (i == u_repl->max_chains)
568                         ebt_double_chains(u_repl);
569                 u_repl->chains[i] = new;
570                 if (i >= NF_BR_NUMHOOKS)
571                         new->kernel_start = (char *)e;
572                 *hook = i;
573                 new->nentries = entries->nentries;
574                 new->policy = entries->policy;
575                 new->entries = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
576                 if (!new->entries)
577                         ebt_print_memory();
578                 new->entries->next = new->entries->prev = new->entries;
579                 new->counter_offset = entries->counter_offset;
580                 strcpy(new->name, entries->name);
581         }
582         return 0;
583 }
584
585 static int retrieve_from_file(char *filename, struct ebt_replace *repl,
586    char command)
587 {
588         FILE *file;
589         char *hlp = NULL, *entries;
590         struct ebt_counter *counters;
591         int size, ret = 0;
592
593         if (!(file = fopen(filename, "r+b"))) {
594                 ebt_print_error("Could not open file %s", filename);
595                 return -1;
596         }
597         /* Make sure table name is right if command isn't -L or --atomic-commit */
598         if (command != 'L' && command != 8) {
599                 hlp = (char *)malloc(strlen(repl->name) + 1);
600                 if (!hlp)
601                         ebt_print_memory();
602                 strcpy(hlp, repl->name);
603         }
604         if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
605            != sizeof(struct ebt_replace)) {
606                 ebt_print_error("File %s is corrupt", filename);
607                 ret = -1;
608                 goto close_file;
609         }
610         if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
611                 ebt_print_error("File %s contains wrong table name or is "
612                                 "corrupt", filename);
613                 ret = -1;
614                 goto close_file;
615         } else if (!ebt_find_table(repl->name)) {
616                 ebt_print_error("File %s contains invalid table name",
617                                 filename);
618                 ret = -1;
619                 goto close_file;
620         }
621
622         size = sizeof(struct ebt_replace) +
623            repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
624         fseek(file, 0, SEEK_END);
625         if (size != ftell(file)) {
626                 ebt_print_error("File %s has wrong size", filename);
627                 ret = -1;
628                 goto close_file;
629         }
630         entries = (char *)malloc(repl->entries_size);
631         if (!entries)
632                 ebt_print_memory();
633         repl->entries = sparc_cast entries;
634         if (repl->nentries) {
635                 counters = (struct ebt_counter *)
636                    malloc(repl->nentries * sizeof(struct ebt_counter));
637                 repl->counters = sparc_cast counters;
638                 if (!repl->counters)
639                         ebt_print_memory();
640         } else
641                 repl->counters = sparc_cast NULL;
642         /* Copy entries and counters */
643         if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
644            fread((char *)repl->entries, sizeof(char), repl->entries_size, file)
645            != repl->entries_size ||
646            fseek(file, sizeof(struct ebt_replace) + repl->entries_size,
647                  SEEK_SET)
648            || (repl->counters && fread((char *)repl->counters, sizeof(char),
649            repl->nentries * sizeof(struct ebt_counter), file)
650            != repl->nentries * sizeof(struct ebt_counter))) {
651                 ebt_print_error("File %s is corrupt", filename);
652                 free(entries);
653                 repl->entries = NULL;
654                 ret = -1;
655         }
656 close_file:
657         fclose(file);
658         free(hlp);
659         return ret;
660 }
661
662 static int retrieve_from_kernel(struct ebt_replace *repl, char command,
663                                 int init)
664 {
665         socklen_t optlen;
666         int optname;
667         char *entries;
668
669         optlen = sizeof(struct ebt_replace);
670         if (get_sockfd())
671                 return -1;
672         /* --atomic-init || --init-table */
673         if (init)
674                 optname = EBT_SO_GET_INIT_INFO;
675         else
676                 optname = EBT_SO_GET_INFO;
677         if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
678                 return -1;
679
680         if ( !(entries = (char *)malloc(repl->entries_size)) )
681                 ebt_print_memory();
682         repl->entries = sparc_cast entries;
683         if (repl->nentries) {
684                 struct ebt_counter *counters;
685
686                 if (!(counters = (struct ebt_counter *)
687                    malloc(repl->nentries * sizeof(struct ebt_counter))) )
688                         ebt_print_memory();
689                 repl->counters = sparc_cast counters;
690         }
691         else
692                 repl->counters = sparc_cast NULL;
693
694         /* We want to receive the counters */
695         repl->num_counters = repl->nentries;
696         optlen += repl->entries_size + repl->num_counters *
697            sizeof(struct ebt_counter);
698         if (init)
699                 optname = EBT_SO_GET_INIT_ENTRIES;
700         else
701                 optname = EBT_SO_GET_ENTRIES;
702         if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
703                 ebt_print_bug("Hmm, what is wrong??? bug#1");
704
705         return 0;
706 }
707
708 int ebt_get_table(struct ebt_u_replace *u_repl, int init)
709 {
710         int i, j, k, hook;
711         struct ebt_replace repl;
712         struct ebt_u_entry *u_e = NULL;
713         struct ebt_cntchanges *new_cc = NULL, *cc;
714
715         strcpy(repl.name, u_repl->name);
716         if (u_repl->filename != NULL) {
717                 if (init)
718                         ebt_print_bug("Getting initial table data from a file is impossible");
719                 if (retrieve_from_file(u_repl->filename, &repl, u_repl->command))
720                         return -1;
721                 /* -L with a wrong table name should be dealt with silently */
722                 strcpy(u_repl->name, repl.name);
723         } else if (retrieve_from_kernel(&repl, u_repl->command, init))
724                 return -1;
725
726         /* Translate the struct ebt_replace to a struct ebt_u_replace */
727         u_repl->valid_hooks = repl.valid_hooks;
728         u_repl->nentries = repl.nentries;
729         u_repl->num_counters = repl.num_counters;
730         u_repl->counters = repl.counters;
731         u_repl->cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
732         if (!u_repl->cc)
733                 ebt_print_memory();
734         u_repl->cc->next = u_repl->cc->prev = u_repl->cc;
735         cc = u_repl->cc;
736         for (i = 0; i < repl.nentries; i++) {
737                 new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
738                 if (!new_cc)
739                         ebt_print_memory();
740                 new_cc->type = CNT_NORM;
741                 new_cc->change = 0;
742                 new_cc->prev = cc;
743                 cc->next = new_cc;
744                 cc = new_cc;
745         }
746         if (repl.nentries) {
747                 new_cc->next = u_repl->cc;
748                 u_repl->cc->prev = new_cc;
749         }
750         u_repl->chains = (struct ebt_u_entries **)calloc(EBT_ORI_MAX_CHAINS, sizeof(void *));
751         u_repl->max_chains = EBT_ORI_MAX_CHAINS;
752         hook = -1;
753         /* FIXME: Clean up when an error is encountered */
754         EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
755            &hook, u_repl, u_repl->valid_hooks);
756         if (hook >= NF_BR_NUMHOOKS)
757                 u_repl->num_chains = hook + 1;
758         else
759                 u_repl->num_chains = NF_BR_NUMHOOKS;
760         i = 0; /* Holds the expected nr. of entries for the chain */
761         j = 0; /* Holds the up to now counted entries for the chain */
762         k = 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */
763         cc = u_repl->cc->next;
764         hook = -1;
765         EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size,
766            ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl,
767            u_repl->valid_hooks, (char *)repl.entries, &cc);
768         if (k != u_repl->nentries)
769                 ebt_print_bug("Wrong total nentries");
770         free(repl.entries);
771         return 0;
772 }