blob: c2455140bc71c77d6efa8cf0137cff3c17b3d817 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
2 * communication.c, v2.0 April 2002
3 *
4 * Author: Bart De Schuymer
5 *
6 */
7
8// All the userspace/kernel communication is in this file.
9// The other code should not have to know anything about the way the
10// kernel likes the structure of the table data.
11// The other code works with linked lists, lots of linked lists.
12// So, the translation is done here.
13
14#include <getopt.h>
15#include <string.h>
16#include <errno.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/socket.h>
20#include <linux/netfilter_bridge/ebtables.h>
21#include <linux/br_db.h> // the database
22#include <netinet/in.h> // IPPROTO_IP
23#include <asm/types.h>
24#include "include/ebtables_u.h"
25
26extern char* hooknames[NF_BR_NUMHOOKS];
27
28int sockfd = -1;
29
Bart De Schuymer62423742002-07-14 19:06:20 +000030static void get_sockfd()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000031{
32 if (sockfd == -1) {
33 sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
34 if (sockfd < 0)
35 print_error("Problem getting a socket");
36 }
37}
38
39static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
40{
41 struct ebt_replace *new;
42 struct ebt_u_entry *e;
43 struct ebt_u_match_list *m_l;
44 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +000045 struct ebt_u_chain_list *cl;
46 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000047 char *p, *base;
48 int i, j;
Bart De Schuymer60332e02002-06-23 08:01:47 +000049 unsigned int entries_size = 0, *chain_offsets;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000050
51 new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
52 if (!new)
53 print_memory();
54 new->valid_hooks = u_repl->valid_hooks;
55 memcpy(new->name, u_repl->name, sizeof(new->name));
56 new->nentries = u_repl->nentries;
57 new->num_counters = u_repl->num_counters;
58 new->counters = u_repl->counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +000059 // determine nr of udc
60 i = 0;
61 cl = u_repl->udc;
62 while (cl) {
63 i++;
64 cl = cl->next;
65 }
66 i += NF_BR_NUMHOOKS;
67 chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000068 // determine size
Bart De Schuymer60332e02002-06-23 08:01:47 +000069 i = 0;
70 cl = u_repl->udc;
71 while (1) {
72 if (i < NF_BR_NUMHOOKS) {
73 if (!(new->valid_hooks & (1 << i))) {
74 i++;
75 continue;
76 }
77 entries = u_repl->hook_entry[i];
78 } else {
79 if (!cl)
80 break;
81 entries = cl->udc;
82 }
83 chain_offsets[i] = entries_size;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000084 entries_size += sizeof(struct ebt_entries);
85 j = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +000086 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000087 while (e) {
88 j++;
89 entries_size += sizeof(struct ebt_entry);
90 m_l = e->m_list;
91 while (m_l) {
92 entries_size += m_l->m->match_size +
93 sizeof(struct ebt_entry_match);
94 m_l = m_l->next;
95 }
96 w_l = e->w_list;
97 while (w_l) {
98 entries_size += w_l->w->watcher_size +
99 sizeof(struct ebt_entry_watcher);
100 w_l = w_l->next;
101 }
102 entries_size += e->t->target_size +
103 sizeof(struct ebt_entry_target);
104 e = e->next;
105 }
106 // a little sanity check
Bart De Schuymer60332e02002-06-23 08:01:47 +0000107 if (j != entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000108 print_bug("Wrong nentries: %d != %d, hook = %s", j,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000109 entries->nentries, entries->name);
110 if (i >= NF_BR_NUMHOOKS)
111 cl = cl->next;
112 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000113 }
114
115 new->entries_size = entries_size;
116 new->entries = (char *)malloc(entries_size);
117 if (!new->entries)
118 print_memory();
119
120 // put everything in one block
121 p = new->entries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000122 i = 0;
123 cl = u_repl->udc;
124 while (1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000125 struct ebt_entries *hlp;
126
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000127 hlp = (struct ebt_entries *)p;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000128 if (i < NF_BR_NUMHOOKS) {
129 if (!(new->valid_hooks & (1 << i))) {
130 i++;
131 continue;
132 }
133 entries = u_repl->hook_entry[i];
134 new->hook_entry[i] = hlp;
135 } else {
136 if (!cl)
137 break;
138 entries = cl->udc;
139 }
140 hlp->nentries = entries->nentries;
141 hlp->policy = entries->policy;
142 strcpy(hlp->name, entries->name);
143 hlp->counter_offset = entries->counter_offset;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000144 hlp->distinguisher = 0; // make the kernel see the light
145 p += sizeof(struct ebt_entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000146 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000147 while (e) {
148 struct ebt_entry *tmp = (struct ebt_entry *)p;
149
150 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
151 tmp->invflags = e->invflags;
152 tmp->ethproto = e->ethproto;
153 memcpy(tmp->in, e->in, sizeof(tmp->in));
154 memcpy(tmp->out, e->out, sizeof(tmp->out));
155 memcpy(tmp->logical_in, e->logical_in,
156 sizeof(tmp->logical_in));
157 memcpy(tmp->logical_out, e->logical_out,
158 sizeof(tmp->logical_out));
159 memcpy(tmp->sourcemac, e->sourcemac,
160 sizeof(tmp->sourcemac));
161 memcpy(tmp->sourcemsk, e->sourcemsk,
162 sizeof(tmp->sourcemsk));
163 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
164 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
165
166 base = p;
167 p += sizeof(struct ebt_entry);
168 m_l = e->m_list;
169 while (m_l) {
170 memcpy(p, m_l->m, m_l->m->match_size +
171 sizeof(struct ebt_entry_match));
172 p += m_l->m->match_size +
173 sizeof(struct ebt_entry_match);
174 m_l = m_l->next;
175 }
176 tmp->watchers_offset = p - base;
177 w_l = e->w_list;
178 while (w_l) {
179 memcpy(p, w_l->w, w_l->w->watcher_size +
180 sizeof(struct ebt_entry_watcher));
181 p += w_l->w->watcher_size +
182 sizeof(struct ebt_entry_watcher);
183 w_l = w_l->next;
184 }
185 tmp->target_offset = p - base;
186 memcpy(p, e->t, e->t->target_size +
187 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000188 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
189 struct ebt_standard_target *st =
190 (struct ebt_standard_target *)p;
191 // translate the jump to a udc
192 if (st->verdict >= 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000193 st->verdict = chain_offsets[st->verdict + NF_BR_NUMHOOKS];
Bart De Schuymer60332e02002-06-23 08:01:47 +0000194 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000195 p += e->t->target_size +
196 sizeof(struct ebt_entry_target);
197 tmp->next_offset = p - base;
198 e = e->next;
199 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000200 if (i >= NF_BR_NUMHOOKS)
201 cl = cl->next;
202 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000203 }
204
205 // sanity check
206 if (p - new->entries != new->entries_size)
207 print_bug("Entries_size bug");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000208 free(chain_offsets);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000209 return new;
210}
211
Bart De Schuymer62423742002-07-14 19:06:20 +0000212static void store_table_in_file(char *filename, struct ebt_replace *repl)
213{
214 char *command, *data;
215 int size;
216 FILE *file;
217
218 // start from an empty file with right priviliges
219 command = (char *)malloc(strlen(filename) + 15);
220 if (!command)
221 print_memory();
222 strcpy(command, "cat /dev/null>");
223 strcpy(command + 14, filename);
224 if (system(command))
225 print_error("Couldn't create file %s", filename);
226 strcpy(command, "chmod 600 ");
227 strcpy(command + 10, filename);
228 if (system(command))
229 print_error("Couldn't chmod file %s", filename);
230 free(command);
231
232 size = sizeof(struct ebt_replace) + repl->entries_size +
233 repl->nentries * sizeof(struct ebt_counter);
234 data = (char *)malloc(size);
235 if (!data)
236 print_memory();
237 memcpy(data, repl, sizeof(struct ebt_replace));
238 memcpy(data + sizeof(struct ebt_replace), repl->entries,
239 repl->entries_size);
240 // initialize counters to zero, deliver_counters() can update them
241 memset(data + sizeof(struct ebt_replace) + repl->entries_size,
242 0, repl->nentries * sizeof(struct ebt_counter));
243 if (!(file = fopen(filename, "wb")))
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000244 print_error("Couldn't open file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000245 if (fwrite(data, sizeof(char), size, file) != size) {
246 fclose(file);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000247 print_error("Couldn't write everything to file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000248 }
249 fclose(file);
250 free(data);
251}
252
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000253void deliver_table(struct ebt_u_replace *u_repl)
254{
255 socklen_t optlen;
256 struct ebt_replace *repl;
257
258 // translate the struct ebt_u_replace to a struct ebt_replace
259 repl = translate_user2kernel(u_repl);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000260 // give the data to the kernel
261 optlen = sizeof(struct ebt_replace) + repl->entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000262 if (u_repl->filename != NULL) {
263 store_table_in_file(u_repl->filename, repl);
264 return;
265 }
266 get_sockfd();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000267 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
Bart De Schuymer73564dc2002-06-05 18:13:51 +0000268 print_error("The kernel doesn't support a certain ebtables"
269 " extension, consider recompiling your kernel or insmod"
270 " the extension");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000271}
272
Bart De Schuymer62423742002-07-14 19:06:20 +0000273static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
274{
275 int size = repl->nentries * sizeof(struct ebt_counter);
276 int entries_size;
277 struct ebt_replace hlp;
278 FILE *file;
279
280 if (!(file = fopen(filename, "r+b")))
281 print_error("Could not open file %s", filename);
282 // find out entries_size and then set the file pointer to the counters
283 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
284 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
285 sizeof(unsigned int) ||
286 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
287 fclose(file);
288 print_error("File %s is corrupt", filename);
289 }
290 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
291 fclose(file);
292 print_error("Could not write everything to file %s", filename);
293 }
294 fclose(file);
295}
296
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000297// gets executed after deliver_table
298void
299deliver_counters(struct ebt_u_replace *u_repl, unsigned short *counterchanges)
300{
301 unsigned short *point;
302 struct ebt_counter *old, *new, *newcounters;
303 socklen_t optlen;
304 struct ebt_replace repl;
305
306 if (u_repl->nentries == 0)
307 return;
308
309 newcounters = (struct ebt_counter *)
310 malloc(u_repl->nentries * sizeof(struct ebt_counter));
311 if (!newcounters)
312 print_memory();
313 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
314 old = u_repl->counters;
315 new = newcounters;
316 point = counterchanges;
317 while (*point != CNT_END) {
318 if (*point == CNT_NORM) {
319 // 'normal' rule, meaning we didn't do anything to it
320 // So, we just copy
321 new->pcnt = old->pcnt;
322 // we've used an old counter
323 old++;
324 // we've set a new counter
325 new++;
326 } else
327 if (*point == CNT_DEL) {
328 // don't use this old counter
329 old++;
330 } else if (*point == CNT_ADD) {
331 // new counter, let it stay 0
332 new++;
333 } else {
334 // zero it
335 new->pcnt = 0;
336 old++;
337 new++;
338 }
339 point++;
340 }
341
342 free(u_repl->counters);
343 u_repl->counters = newcounters;
344 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000345 if (u_repl->filename != NULL) {
346 store_counters_in_file(u_repl->filename, u_repl);
347 return;
348 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000349 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
350 sizeof(struct ebt_replace);
351 // now put the stuff in the kernel's struct ebt_replace
352 repl.counters = u_repl->counters;
353 repl.num_counters = u_repl->num_counters;
354 memcpy(repl.name, u_repl->name, sizeof(repl.name));
355
356 get_sockfd();
357 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
358 print_bug("couldn't update kernel counters");
359}
360
361static int
362ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
363{
364 struct ebt_u_match_list *new;
365
366 new = (struct ebt_u_match_list *)
367 malloc(sizeof(struct ebt_u_match_list));
368 if (!new)
369 print_memory();
370 new->m = (struct ebt_entry_match *)
371 malloc(m->match_size + sizeof(struct ebt_entry_match));
372 if (!new->m)
373 print_memory();
374 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
375 new->next = NULL;
376 **l = new;
377 *l = &new->next;
378 if (find_match(new->m->u.name) == NULL)
379 print_error("Kernel match %s unsupported by userspace tool",
380 new->m->u.name);
381 return 0;
382}
383
384static int
385ebt_translate_watcher(struct ebt_entry_watcher *w,
386 struct ebt_u_watcher_list ***l)
387{
388 struct ebt_u_watcher_list *new;
389
390 new = (struct ebt_u_watcher_list *)
391 malloc(sizeof(struct ebt_u_watcher_list));
392 if (!new)
393 print_memory();
394 new->w = (struct ebt_entry_watcher *)
395 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
396 if (!new->w)
397 print_memory();
398 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
399 new->next = NULL;
400 **l = new;
401 *l = &new->next;
402 if (find_watcher(new->w->u.name) == NULL)
403 print_error("Kernel watcher %s unsupported by userspace tool",
404 new->w->u.name);
405 return 0;
406}
407
408static int
409ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
410 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000411 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000412{
413 // an entry
414 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
415 struct ebt_u_entry *new;
416 struct ebt_u_match_list **m_l;
417 struct ebt_u_watcher_list **w_l;
418 struct ebt_entry_target *t;
419
420 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
421 if (!new)
422 print_memory();
423 new->bitmask = e->bitmask;
424 // plain userspace code doesn't know about EBT_ENTRY_OR_ENTRIES
425 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
426 new->invflags = e->invflags;
427 new->ethproto = e->ethproto;
428 memcpy(new->in, e->in, sizeof(new->in));
429 memcpy(new->out, e->out, sizeof(new->out));
430 memcpy(new->logical_in, e->logical_in,
431 sizeof(new->logical_in));
432 memcpy(new->logical_out, e->logical_out,
433 sizeof(new->logical_out));
434 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
435 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
436 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
437 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
438 new->m_list = NULL;
439 new->w_list = NULL;
440 new->next = NULL;
441 m_l = &new->m_list;
442 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
443 w_l = &new->w_list;
444 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
445
446 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
447 new->t = (struct ebt_entry_target *)
448 malloc(t->target_size + sizeof(struct ebt_entry_target));
449 if (!new->t)
450 print_memory();
451 if (find_target(t->u.name) == NULL)
452 print_error("Kernel target %s unsupported by "
453 "userspace tool", t->u.name);
454 memcpy(new->t, t, t->target_size +
455 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000456 // deal with jumps to udc
457 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
458 char *tmp = base;
459 int verdict = ((struct ebt_standard_target *)t)->verdict;
460 int i;
461 struct ebt_u_chain_list *cl;
462
463 if (verdict >= 0) {
464 tmp += verdict;
465 cl = u_repl->udc;
466 i = 0;
467 while (cl && cl->kernel_start != tmp) {
468 i++;
469 cl = cl->next;
470 }
471 if (!cl)
472 print_bug("can't find udc for jump");
473 ((struct ebt_standard_target *)new->t)->verdict = i;
474 }
475 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000476
477 // I love pointers
478 **u_e = new;
479 *u_e = &new->next;
480 (*cnt)++;
481 (*totalcnt)++;
482 return 0;
483 } else { // a new chain
484 int i;
485 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000486 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000487
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000488 if (*n != *cnt)
489 print_bug("Nr of entries in the chain is wrong");
490 *n = entries->nentries;
491 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000492 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
493 if (valid_hooks & (1 << i))
494 break;
495 *hook = i;
496 // makes use of fact that standard chains come before udc
497 if (i >= NF_BR_NUMHOOKS) { // udc
498 i -= NF_BR_NUMHOOKS;
499 cl = u_repl->udc;
500 while (i-- > 0)
501 cl = cl->next;
502 *u_e = &(cl->udc->entries);
503 } else {
504 *u_e = &(u_repl->hook_entry[*hook]->entries);
505 }
506 return 0;
507 }
508}
509
510// initialize all chain headers
511static int
512ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
513 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
514{
515 int i;
516 struct ebt_entries *entries = (struct ebt_entries *)e;
517 struct ebt_u_entries *new;
518 struct ebt_u_chain_list **chain_list;
519
520 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
521 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
522 if (valid_hooks & (1 << i))
523 break;
524 // makes use of fact that standard chains come before udc
525 if (i >= NF_BR_NUMHOOKS) { // udc
526 chain_list = &u_repl->udc;
527 // add in the back
528 while (*chain_list)
529 chain_list = &((*chain_list)->next);
530 *chain_list = (struct ebt_u_chain_list *)
531 malloc(sizeof(struct ebt_u_chain_list));
532 if (!(*chain_list))
533 print_memory();
534 (*chain_list)->next = NULL;
535 (*chain_list)->udc = (struct ebt_u_entries *)
536 malloc(sizeof(struct ebt_u_entries));
537 if (!((*chain_list)->udc))
538 print_memory();
539 new = (*chain_list)->udc;
540 // ebt_translate_entry depends on this for knowing
541 // to which chain is being jumped
542 (*chain_list)->kernel_start = (char *)e;
543 } else {
544 *hook = i;
545 new = (struct ebt_u_entries *)
546 malloc(sizeof(struct ebt_u_entries));
547 if (!new)
548 print_memory();
549 u_repl->hook_entry[*hook] = new;
550 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000551 new->nentries = entries->nentries;
552 new->policy = entries->policy;
553 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000554 new->counter_offset = entries->counter_offset;
555 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000556 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000557 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000558}
559
Bart De Schuymer62423742002-07-14 19:06:20 +0000560static void retrieve_from_file(char *filename, struct ebt_replace *repl,
561 char command)
562{
563 FILE *file;
564 char *hlp;
565 int size;
566
567 if (!(file = fopen(filename, "r+b")))
568 print_error("Could not open file %s", filename);
569 // make sure table name is right if command isn't -L or --atomic-commit
570 if (command != 'L' && command != 8) {
571 hlp = (char *)malloc(strlen(repl->name));
572 if (!hlp)
573 print_memory();
574 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000575 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000576 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
577 != sizeof(struct ebt_replace))
578 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000579 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
580 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000581 print_error("File %s contains wrong table name or is corrupt",
582 filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000583 } else
584 if (!find_table(repl->name)) {
585 fclose(file);
586 print_error("File %s contains invalid table name",
587 filename);
588 }
589
Bart De Schuymer62423742002-07-14 19:06:20 +0000590 size = sizeof(struct ebt_replace) +
591 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
592 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000593 if (size != ftell(file)) {
594 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000595 print_error("File %s has wrong size", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000596 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000597 repl->entries = (char *)malloc(repl->entries_size);
598 if (!repl->entries)
599 print_memory();
600 if (repl->nentries) {
601 repl->counters = (struct ebt_counter *)
602 malloc(repl->nentries * sizeof(struct ebt_counter));
603 if (!repl->counters)
604 print_memory();
605 } else
606 repl->counters = NULL;
607 // copy entries and counters
608 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
609 fread(repl->entries, sizeof(char), repl->entries_size, file)
610 != repl->entries_size ||
611 fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
612 || fread(repl->counters, sizeof(char),
613 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000614 != repl->nentries * sizeof(struct ebt_counter)) {
615 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000616 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000617 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000618 fclose(file);
619}
620
621static int retrieve_from_kernel(struct ebt_replace *repl, char command)
622{
623 socklen_t optlen;
624 int optname;
625
626 optlen = sizeof(struct ebt_replace);
627 get_sockfd();
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000628 // --atomic-init || --init-table
629 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000630 optname = EBT_SO_GET_INIT_INFO;
631 else
632 optname = EBT_SO_GET_INFO;
633 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
634 return -1;
635
636 if ( !(repl->entries = (char *) malloc(repl->entries_size)) )
637 print_memory();
638 if (repl->nentries) {
639 if (!(repl->counters = (struct ebt_counter *)
640 malloc(repl->nentries * sizeof(struct ebt_counter))) )
641 print_memory();
642 }
643 else
644 repl->counters = NULL;
645
646 // we want to receive the counters
647 repl->num_counters = repl->nentries;
648 optlen += repl->entries_size + repl->num_counters *
649 sizeof(struct ebt_counter);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000650 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000651 optname = EBT_SO_GET_INIT_ENTRIES;
652 else
653 optname = EBT_SO_GET_ENTRIES;
654 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
655 print_bug("hmm, what is wrong??? bug#1");
656
657 return 0;
658}
659
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000660// talk with kernel to receive the kernel's table
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000661int get_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000662{
663 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000664 struct ebt_replace repl;
665 struct ebt_u_entry **u_e;
666
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000667 strcpy(repl.name, u_repl->name);
Bart De Schuymer62423742002-07-14 19:06:20 +0000668 if (u_repl->filename != NULL)
669 retrieve_from_file(u_repl->filename, &repl, u_repl->command);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000670 else
Bart De Schuymer62423742002-07-14 19:06:20 +0000671 if (retrieve_from_kernel(&repl, u_repl->command) == -1)
672 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000673
674 // translate the struct ebt_replace to a struct ebt_u_replace
675 memcpy(u_repl->name, repl.name, sizeof(u_repl->name));
676 u_repl->valid_hooks = repl.valid_hooks;
677 u_repl->nentries = repl.nentries;
678 u_repl->num_counters = repl.num_counters;
679 u_repl->counters = repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000680 u_repl->udc = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000681 hook = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000682 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
683 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000684 i = 0; // holds the expected nr. of entries for the chain
685 j = 0; // holds the up to now counted entries for the chain
686 k = 0; // holds the total nr. of entries,
687 // should equal u_repl->nentries afterwards
Bart De Schuymer60332e02002-06-23 08:01:47 +0000688 hook = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000689 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000690 &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks, repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000691 if (k != u_repl->nentries)
692 print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000693 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000694}
695
696void get_dbinfo(struct brdb_dbinfo *nr)
697{
698 socklen_t optlen = sizeof(struct brdb_dbinfo);
699
700 get_sockfd();
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000701
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000702 if (getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DBINFO, nr, &optlen))
703 print_error("Sorry, br_db code probably not in kernel, "
704 "try insmod br_db");
705}
706
707void get_db(int len, struct brdb_dbentry *db)
708{
709 socklen_t optlen = len;
710
711 get_sockfd();
712
713 if ( getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DB, db, &optlen) ) {
714 print_bug("hmm, what is wrong??? bug#2");
715 }
716}
717
718void deliver_allowdb(__u16 *decision)
719{
720 socklen_t optlen = sizeof(__u16);
721
722 get_sockfd();
723
724 if (setsockopt(sockfd, IPPROTO_IP, BRDB_SO_SET_ALLOWDB,
725 decision, optlen))
726 print_error("Sorry, br_db code probably not in kernel, "
727 "try insmod br_db");
728}