blob: d0f41398b7b6f065d71e224fabbc4bbf427306d2 [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
Bart De Schuymered053432002-07-21 19:35:39 +0000299deliver_counters(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000300{
301 unsigned short *point;
302 struct ebt_counter *old, *new, *newcounters;
303 socklen_t optlen;
304 struct ebt_replace repl;
Bart De Schuymered053432002-07-21 19:35:39 +0000305 unsigned short *counterchanges = u_repl->counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000306
307 if (u_repl->nentries == 0)
308 return;
309
310 newcounters = (struct ebt_counter *)
311 malloc(u_repl->nentries * sizeof(struct ebt_counter));
312 if (!newcounters)
313 print_memory();
314 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
315 old = u_repl->counters;
316 new = newcounters;
317 point = counterchanges;
318 while (*point != CNT_END) {
319 if (*point == CNT_NORM) {
320 // 'normal' rule, meaning we didn't do anything to it
321 // So, we just copy
322 new->pcnt = old->pcnt;
323 // we've used an old counter
324 old++;
325 // we've set a new counter
326 new++;
327 } else
328 if (*point == CNT_DEL) {
329 // don't use this old counter
330 old++;
331 } else if (*point == CNT_ADD) {
332 // new counter, let it stay 0
333 new++;
334 } else {
335 // zero it
336 new->pcnt = 0;
337 old++;
338 new++;
339 }
340 point++;
341 }
342
343 free(u_repl->counters);
344 u_repl->counters = newcounters;
345 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000346 if (u_repl->filename != NULL) {
347 store_counters_in_file(u_repl->filename, u_repl);
348 return;
349 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000350 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
351 sizeof(struct ebt_replace);
352 // now put the stuff in the kernel's struct ebt_replace
353 repl.counters = u_repl->counters;
354 repl.num_counters = u_repl->num_counters;
355 memcpy(repl.name, u_repl->name, sizeof(repl.name));
356
357 get_sockfd();
358 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
359 print_bug("couldn't update kernel counters");
360}
361
362static int
363ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
364{
365 struct ebt_u_match_list *new;
366
367 new = (struct ebt_u_match_list *)
368 malloc(sizeof(struct ebt_u_match_list));
369 if (!new)
370 print_memory();
371 new->m = (struct ebt_entry_match *)
372 malloc(m->match_size + sizeof(struct ebt_entry_match));
373 if (!new->m)
374 print_memory();
375 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
376 new->next = NULL;
377 **l = new;
378 *l = &new->next;
379 if (find_match(new->m->u.name) == NULL)
380 print_error("Kernel match %s unsupported by userspace tool",
381 new->m->u.name);
382 return 0;
383}
384
385static int
386ebt_translate_watcher(struct ebt_entry_watcher *w,
387 struct ebt_u_watcher_list ***l)
388{
389 struct ebt_u_watcher_list *new;
390
391 new = (struct ebt_u_watcher_list *)
392 malloc(sizeof(struct ebt_u_watcher_list));
393 if (!new)
394 print_memory();
395 new->w = (struct ebt_entry_watcher *)
396 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
397 if (!new->w)
398 print_memory();
399 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
400 new->next = NULL;
401 **l = new;
402 *l = &new->next;
403 if (find_watcher(new->w->u.name) == NULL)
404 print_error("Kernel watcher %s unsupported by userspace tool",
405 new->w->u.name);
406 return 0;
407}
408
409static int
410ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
411 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000412 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000413{
414 // an entry
415 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
416 struct ebt_u_entry *new;
417 struct ebt_u_match_list **m_l;
418 struct ebt_u_watcher_list **w_l;
419 struct ebt_entry_target *t;
420
421 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
422 if (!new)
423 print_memory();
424 new->bitmask = e->bitmask;
425 // plain userspace code doesn't know about EBT_ENTRY_OR_ENTRIES
426 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
427 new->invflags = e->invflags;
428 new->ethproto = e->ethproto;
429 memcpy(new->in, e->in, sizeof(new->in));
430 memcpy(new->out, e->out, sizeof(new->out));
431 memcpy(new->logical_in, e->logical_in,
432 sizeof(new->logical_in));
433 memcpy(new->logical_out, e->logical_out,
434 sizeof(new->logical_out));
435 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
436 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
437 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
438 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
439 new->m_list = NULL;
440 new->w_list = NULL;
441 new->next = NULL;
442 m_l = &new->m_list;
443 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
444 w_l = &new->w_list;
445 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
446
447 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
448 new->t = (struct ebt_entry_target *)
449 malloc(t->target_size + sizeof(struct ebt_entry_target));
450 if (!new->t)
451 print_memory();
452 if (find_target(t->u.name) == NULL)
453 print_error("Kernel target %s unsupported by "
454 "userspace tool", t->u.name);
455 memcpy(new->t, t, t->target_size +
456 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000457 // deal with jumps to udc
458 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
459 char *tmp = base;
460 int verdict = ((struct ebt_standard_target *)t)->verdict;
461 int i;
462 struct ebt_u_chain_list *cl;
463
464 if (verdict >= 0) {
465 tmp += verdict;
466 cl = u_repl->udc;
467 i = 0;
468 while (cl && cl->kernel_start != tmp) {
469 i++;
470 cl = cl->next;
471 }
472 if (!cl)
473 print_bug("can't find udc for jump");
474 ((struct ebt_standard_target *)new->t)->verdict = i;
475 }
476 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000477
478 // I love pointers
479 **u_e = new;
480 *u_e = &new->next;
481 (*cnt)++;
482 (*totalcnt)++;
483 return 0;
484 } else { // a new chain
485 int i;
486 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000487 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000488
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000489 if (*n != *cnt)
490 print_bug("Nr of entries in the chain is wrong");
491 *n = entries->nentries;
492 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000493 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
494 if (valid_hooks & (1 << i))
495 break;
496 *hook = i;
497 // makes use of fact that standard chains come before udc
498 if (i >= NF_BR_NUMHOOKS) { // udc
499 i -= NF_BR_NUMHOOKS;
500 cl = u_repl->udc;
501 while (i-- > 0)
502 cl = cl->next;
503 *u_e = &(cl->udc->entries);
504 } else {
505 *u_e = &(u_repl->hook_entry[*hook]->entries);
506 }
507 return 0;
508 }
509}
510
511// initialize all chain headers
512static int
513ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
514 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
515{
516 int i;
517 struct ebt_entries *entries = (struct ebt_entries *)e;
518 struct ebt_u_entries *new;
519 struct ebt_u_chain_list **chain_list;
520
521 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
522 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
523 if (valid_hooks & (1 << i))
524 break;
525 // makes use of fact that standard chains come before udc
526 if (i >= NF_BR_NUMHOOKS) { // udc
527 chain_list = &u_repl->udc;
528 // add in the back
529 while (*chain_list)
530 chain_list = &((*chain_list)->next);
531 *chain_list = (struct ebt_u_chain_list *)
532 malloc(sizeof(struct ebt_u_chain_list));
533 if (!(*chain_list))
534 print_memory();
535 (*chain_list)->next = NULL;
536 (*chain_list)->udc = (struct ebt_u_entries *)
537 malloc(sizeof(struct ebt_u_entries));
538 if (!((*chain_list)->udc))
539 print_memory();
540 new = (*chain_list)->udc;
541 // ebt_translate_entry depends on this for knowing
542 // to which chain is being jumped
543 (*chain_list)->kernel_start = (char *)e;
544 } else {
545 *hook = i;
546 new = (struct ebt_u_entries *)
547 malloc(sizeof(struct ebt_u_entries));
548 if (!new)
549 print_memory();
550 u_repl->hook_entry[*hook] = new;
551 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000552 new->nentries = entries->nentries;
553 new->policy = entries->policy;
554 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000555 new->counter_offset = entries->counter_offset;
556 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000557 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000558 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000559}
560
Bart De Schuymer62423742002-07-14 19:06:20 +0000561static void retrieve_from_file(char *filename, struct ebt_replace *repl,
562 char command)
563{
564 FILE *file;
565 char *hlp;
566 int size;
567
568 if (!(file = fopen(filename, "r+b")))
569 print_error("Could not open file %s", filename);
570 // make sure table name is right if command isn't -L or --atomic-commit
571 if (command != 'L' && command != 8) {
572 hlp = (char *)malloc(strlen(repl->name));
573 if (!hlp)
574 print_memory();
575 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000576 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000577 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
578 != sizeof(struct ebt_replace))
579 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000580 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
581 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000582 print_error("File %s contains wrong table name or is corrupt",
583 filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000584 } else
585 if (!find_table(repl->name)) {
586 fclose(file);
587 print_error("File %s contains invalid table name",
588 filename);
589 }
590
Bart De Schuymer62423742002-07-14 19:06:20 +0000591 size = sizeof(struct ebt_replace) +
592 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
593 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000594 if (size != ftell(file)) {
595 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000596 print_error("File %s has wrong size", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000597 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000598 repl->entries = (char *)malloc(repl->entries_size);
599 if (!repl->entries)
600 print_memory();
601 if (repl->nentries) {
602 repl->counters = (struct ebt_counter *)
603 malloc(repl->nentries * sizeof(struct ebt_counter));
604 if (!repl->counters)
605 print_memory();
606 } else
607 repl->counters = NULL;
608 // copy entries and counters
609 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
610 fread(repl->entries, sizeof(char), repl->entries_size, file)
611 != repl->entries_size ||
612 fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
613 || fread(repl->counters, sizeof(char),
614 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000615 != repl->nentries * sizeof(struct ebt_counter)) {
616 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000617 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000618 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000619 fclose(file);
620}
621
622static int retrieve_from_kernel(struct ebt_replace *repl, char command)
623{
624 socklen_t optlen;
625 int optname;
626
627 optlen = sizeof(struct ebt_replace);
628 get_sockfd();
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000629 // --atomic-init || --init-table
630 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000631 optname = EBT_SO_GET_INIT_INFO;
632 else
633 optname = EBT_SO_GET_INFO;
634 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
635 return -1;
636
637 if ( !(repl->entries = (char *) malloc(repl->entries_size)) )
638 print_memory();
639 if (repl->nentries) {
640 if (!(repl->counters = (struct ebt_counter *)
641 malloc(repl->nentries * sizeof(struct ebt_counter))) )
642 print_memory();
643 }
644 else
645 repl->counters = NULL;
646
647 // we want to receive the counters
648 repl->num_counters = repl->nentries;
649 optlen += repl->entries_size + repl->num_counters *
650 sizeof(struct ebt_counter);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000651 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000652 optname = EBT_SO_GET_INIT_ENTRIES;
653 else
654 optname = EBT_SO_GET_ENTRIES;
655 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
656 print_bug("hmm, what is wrong??? bug#1");
657
658 return 0;
659}
660
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000661// talk with kernel to receive the kernel's table
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000662int get_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000663{
664 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000665 struct ebt_replace repl;
666 struct ebt_u_entry **u_e;
667
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000668 strcpy(repl.name, u_repl->name);
Bart De Schuymer62423742002-07-14 19:06:20 +0000669 if (u_repl->filename != NULL)
670 retrieve_from_file(u_repl->filename, &repl, u_repl->command);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000671 else
Bart De Schuymer62423742002-07-14 19:06:20 +0000672 if (retrieve_from_kernel(&repl, u_repl->command) == -1)
673 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000674
675 // translate the struct ebt_replace to a struct ebt_u_replace
676 memcpy(u_repl->name, repl.name, sizeof(u_repl->name));
677 u_repl->valid_hooks = repl.valid_hooks;
678 u_repl->nentries = repl.nentries;
679 u_repl->num_counters = repl.num_counters;
680 u_repl->counters = repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000681 u_repl->udc = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000682 hook = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000683 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
684 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000685 i = 0; // holds the expected nr. of entries for the chain
686 j = 0; // holds the up to now counted entries for the chain
687 k = 0; // holds the total nr. of entries,
688 // should equal u_repl->nentries afterwards
Bart De Schuymer60332e02002-06-23 08:01:47 +0000689 hook = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000690 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000691 &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks, repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000692 if (k != u_repl->nentries)
693 print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000694 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000695}
696
697void get_dbinfo(struct brdb_dbinfo *nr)
698{
699 socklen_t optlen = sizeof(struct brdb_dbinfo);
700
701 get_sockfd();
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000702
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000703 if (getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DBINFO, nr, &optlen))
704 print_error("Sorry, br_db code probably not in kernel, "
705 "try insmod br_db");
706}
707
708void get_db(int len, struct brdb_dbentry *db)
709{
710 socklen_t optlen = len;
711
712 get_sockfd();
713
714 if ( getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DB, db, &optlen) ) {
715 print_bug("hmm, what is wrong??? bug#2");
716 }
717}
718
719void deliver_allowdb(__u16 *decision)
720{
721 socklen_t optlen = sizeof(__u16);
722
723 get_sockfd();
724
725 if (setsockopt(sockfd, IPPROTO_IP, BRDB_SO_SET_ALLOWDB,
726 decision, optlen))
727 print_error("Sorry, br_db code probably not in kernel, "
728 "try insmod br_db");
729}