blob: 6414f6638b348807468ba724e106db1b65d6b345 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
Bart De Schuymer0cff9e92002-07-25 12:29:50 +00002 * communication.c, v2.0 July 2002
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00003 *
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>
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000021#include <linux/br_db.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000022#include <netinet/in.h> // IPPROTO_IP
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000023#include "include/ebtables_u.h"
24
25extern char* hooknames[NF_BR_NUMHOOKS];
26
27int sockfd = -1;
28
Bart De Schuymer62423742002-07-14 19:06:20 +000029static void get_sockfd()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000030{
31 if (sockfd == -1) {
32 sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
33 if (sockfd < 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000034 print_error("Problem getting a socket, "
Bart De Schuymere3cceb72002-07-26 12:47:33 +000035 "do you have the right permissions?");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000036 }
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;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000055 strcpy(new->name, u_repl->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000056 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;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000153 strcpy(tmp->in, e->in);
154 strcpy(tmp->out, e->out);
155 strcpy(tmp->logical_in, e->logical_in);
156 strcpy(tmp->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000157 memcpy(tmp->sourcemac, e->sourcemac,
158 sizeof(tmp->sourcemac));
159 memcpy(tmp->sourcemsk, e->sourcemsk,
160 sizeof(tmp->sourcemsk));
161 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
162 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
163
164 base = p;
165 p += sizeof(struct ebt_entry);
166 m_l = e->m_list;
167 while (m_l) {
168 memcpy(p, m_l->m, m_l->m->match_size +
169 sizeof(struct ebt_entry_match));
170 p += m_l->m->match_size +
171 sizeof(struct ebt_entry_match);
172 m_l = m_l->next;
173 }
174 tmp->watchers_offset = p - base;
175 w_l = e->w_list;
176 while (w_l) {
177 memcpy(p, w_l->w, w_l->w->watcher_size +
178 sizeof(struct ebt_entry_watcher));
179 p += w_l->w->watcher_size +
180 sizeof(struct ebt_entry_watcher);
181 w_l = w_l->next;
182 }
183 tmp->target_offset = p - base;
184 memcpy(p, e->t, e->t->target_size +
185 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000186 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
187 struct ebt_standard_target *st =
188 (struct ebt_standard_target *)p;
189 // translate the jump to a udc
190 if (st->verdict >= 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000191 st->verdict = chain_offsets
192 [st->verdict + NF_BR_NUMHOOKS];
Bart De Schuymer60332e02002-06-23 08:01:47 +0000193 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000194 p += e->t->target_size +
195 sizeof(struct ebt_entry_target);
196 tmp->next_offset = p - base;
197 e = e->next;
198 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000199 if (i >= NF_BR_NUMHOOKS)
200 cl = cl->next;
201 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000202 }
203
204 // sanity check
205 if (p - new->entries != new->entries_size)
206 print_bug("Entries_size bug");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000207 free(chain_offsets);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000208 return new;
209}
210
Bart De Schuymer62423742002-07-14 19:06:20 +0000211static void store_table_in_file(char *filename, struct ebt_replace *repl)
212{
213 char *command, *data;
214 int size;
215 FILE *file;
216
217 // start from an empty file with right priviliges
218 command = (char *)malloc(strlen(filename) + 15);
219 if (!command)
220 print_memory();
221 strcpy(command, "cat /dev/null>");
222 strcpy(command + 14, filename);
223 if (system(command))
224 print_error("Couldn't create file %s", filename);
225 strcpy(command, "chmod 600 ");
226 strcpy(command + 10, filename);
227 if (system(command))
228 print_error("Couldn't chmod file %s", filename);
229 free(command);
230
231 size = sizeof(struct ebt_replace) + repl->entries_size +
232 repl->nentries * sizeof(struct ebt_counter);
233 data = (char *)malloc(size);
234 if (!data)
235 print_memory();
236 memcpy(data, repl, sizeof(struct ebt_replace));
237 memcpy(data + sizeof(struct ebt_replace), repl->entries,
238 repl->entries_size);
239 // initialize counters to zero, deliver_counters() can update them
240 memset(data + sizeof(struct ebt_replace) + repl->entries_size,
241 0, repl->nentries * sizeof(struct ebt_counter));
242 if (!(file = fopen(filename, "wb")))
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000243 print_error("Couldn't open file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000244 if (fwrite(data, sizeof(char), size, file) != size) {
245 fclose(file);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000246 print_error("Couldn't write everything to file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000247 }
248 fclose(file);
249 free(data);
250}
251
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000252void deliver_table(struct ebt_u_replace *u_repl)
253{
254 socklen_t optlen;
255 struct ebt_replace *repl;
256
257 // translate the struct ebt_u_replace to a struct ebt_replace
258 repl = translate_user2kernel(u_repl);
Bart De Schuymer62423742002-07-14 19:06:20 +0000259 if (u_repl->filename != NULL) {
260 store_table_in_file(u_repl->filename, repl);
261 return;
262 }
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000263 // give the data to the kernel
264 optlen = sizeof(struct ebt_replace) + repl->entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000265 get_sockfd();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000266 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
Bart De Schuymer73564dc2002-06-05 18:13:51 +0000267 print_error("The kernel doesn't support a certain ebtables"
268 " extension, consider recompiling your kernel or insmod"
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000269 " the extension");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000270}
271
Bart De Schuymer62423742002-07-14 19:06:20 +0000272static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
273{
274 int size = repl->nentries * sizeof(struct ebt_counter);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000275 unsigned int entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000276 struct ebt_replace hlp;
277 FILE *file;
278
279 if (!(file = fopen(filename, "r+b")))
280 print_error("Could not open file %s", filename);
281 // find out entries_size and then set the file pointer to the counters
282 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
283 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
284 sizeof(unsigned int) ||
285 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
286 fclose(file);
287 print_error("File %s is corrupt", filename);
288 }
289 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
290 fclose(file);
291 print_error("Could not write everything to file %s", filename);
292 }
293 fclose(file);
294}
295
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000296// gets executed after deliver_table
297void
Bart De Schuymered053432002-07-21 19:35:39 +0000298deliver_counters(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000299{
300 unsigned short *point;
301 struct ebt_counter *old, *new, *newcounters;
302 socklen_t optlen;
303 struct ebt_replace repl;
Bart De Schuymered053432002-07-21 19:35:39 +0000304 unsigned short *counterchanges = u_repl->counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000305
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++;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000326 } else if (*point == CNT_DEL) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000327 // don't use this old counter
328 old++;
329 } else if (*point == CNT_ADD) {
330 // new counter, let it stay 0
331 new++;
332 } else {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000333 // zero it (let it stay 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000334 old++;
335 new++;
336 }
337 point++;
338 }
339
340 free(u_repl->counters);
341 u_repl->counters = newcounters;
342 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000343 if (u_repl->filename != NULL) {
344 store_counters_in_file(u_repl->filename, u_repl);
345 return;
346 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000347 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
348 sizeof(struct ebt_replace);
349 // now put the stuff in the kernel's struct ebt_replace
350 repl.counters = u_repl->counters;
351 repl.num_counters = u_repl->num_counters;
352 memcpy(repl.name, u_repl->name, sizeof(repl.name));
353
354 get_sockfd();
355 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000356 print_bug("Couldn't update kernel counters");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000357}
358
359static int
360ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
361{
362 struct ebt_u_match_list *new;
363
364 new = (struct ebt_u_match_list *)
365 malloc(sizeof(struct ebt_u_match_list));
366 if (!new)
367 print_memory();
368 new->m = (struct ebt_entry_match *)
369 malloc(m->match_size + sizeof(struct ebt_entry_match));
370 if (!new->m)
371 print_memory();
372 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
373 new->next = NULL;
374 **l = new;
375 *l = &new->next;
376 if (find_match(new->m->u.name) == NULL)
377 print_error("Kernel match %s unsupported by userspace tool",
378 new->m->u.name);
379 return 0;
380}
381
382static int
383ebt_translate_watcher(struct ebt_entry_watcher *w,
384 struct ebt_u_watcher_list ***l)
385{
386 struct ebt_u_watcher_list *new;
387
388 new = (struct ebt_u_watcher_list *)
389 malloc(sizeof(struct ebt_u_watcher_list));
390 if (!new)
391 print_memory();
392 new->w = (struct ebt_entry_watcher *)
393 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
394 if (!new->w)
395 print_memory();
396 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
397 new->next = NULL;
398 **l = new;
399 *l = &new->next;
400 if (find_watcher(new->w->u.name) == NULL)
401 print_error("Kernel watcher %s unsupported by userspace tool",
402 new->w->u.name);
403 return 0;
404}
405
406static int
407ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
408 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000409 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000410{
411 // an entry
412 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
413 struct ebt_u_entry *new;
414 struct ebt_u_match_list **m_l;
415 struct ebt_u_watcher_list **w_l;
416 struct ebt_entry_target *t;
417
418 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
419 if (!new)
420 print_memory();
421 new->bitmask = e->bitmask;
422 // plain userspace code doesn't know about EBT_ENTRY_OR_ENTRIES
423 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
424 new->invflags = e->invflags;
425 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000426 strcpy(new->in, e->in);
427 strcpy(new->out, e->out);
428 strcpy(new->logical_in, e->logical_in);
429 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000430 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
431 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
432 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
433 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
434 new->m_list = NULL;
435 new->w_list = NULL;
436 new->next = NULL;
437 m_l = &new->m_list;
438 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
439 w_l = &new->w_list;
440 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
441
442 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
443 new->t = (struct ebt_entry_target *)
444 malloc(t->target_size + sizeof(struct ebt_entry_target));
445 if (!new->t)
446 print_memory();
447 if (find_target(t->u.name) == NULL)
448 print_error("Kernel target %s unsupported by "
449 "userspace tool", t->u.name);
450 memcpy(new->t, t, t->target_size +
451 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000452 // deal with jumps to udc
453 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
454 char *tmp = base;
455 int verdict = ((struct ebt_standard_target *)t)->verdict;
456 int i;
457 struct ebt_u_chain_list *cl;
458
459 if (verdict >= 0) {
460 tmp += verdict;
461 cl = u_repl->udc;
462 i = 0;
463 while (cl && cl->kernel_start != tmp) {
464 i++;
465 cl = cl->next;
466 }
467 if (!cl)
468 print_bug("can't find udc for jump");
469 ((struct ebt_standard_target *)new->t)->verdict = i;
470 }
471 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000472
473 // I love pointers
474 **u_e = new;
475 *u_e = &new->next;
476 (*cnt)++;
477 (*totalcnt)++;
478 return 0;
479 } else { // a new chain
480 int i;
481 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000482 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000483
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000484 if (*n != *cnt)
485 print_bug("Nr of entries in the chain is wrong");
486 *n = entries->nentries;
487 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000488 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
489 if (valid_hooks & (1 << i))
490 break;
491 *hook = i;
492 // makes use of fact that standard chains come before udc
493 if (i >= NF_BR_NUMHOOKS) { // udc
494 i -= NF_BR_NUMHOOKS;
495 cl = u_repl->udc;
496 while (i-- > 0)
497 cl = cl->next;
498 *u_e = &(cl->udc->entries);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000499 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000500 *u_e = &(u_repl->hook_entry[*hook]->entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000501 return 0;
502 }
503}
504
505// initialize all chain headers
506static int
507ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
508 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
509{
510 int i;
511 struct ebt_entries *entries = (struct ebt_entries *)e;
512 struct ebt_u_entries *new;
513 struct ebt_u_chain_list **chain_list;
514
515 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
516 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
517 if (valid_hooks & (1 << i))
518 break;
519 // makes use of fact that standard chains come before udc
520 if (i >= NF_BR_NUMHOOKS) { // udc
521 chain_list = &u_repl->udc;
522 // add in the back
523 while (*chain_list)
524 chain_list = &((*chain_list)->next);
525 *chain_list = (struct ebt_u_chain_list *)
526 malloc(sizeof(struct ebt_u_chain_list));
527 if (!(*chain_list))
528 print_memory();
529 (*chain_list)->next = NULL;
530 (*chain_list)->udc = (struct ebt_u_entries *)
531 malloc(sizeof(struct ebt_u_entries));
532 if (!((*chain_list)->udc))
533 print_memory();
534 new = (*chain_list)->udc;
535 // ebt_translate_entry depends on this for knowing
536 // to which chain is being jumped
537 (*chain_list)->kernel_start = (char *)e;
538 } else {
539 *hook = i;
540 new = (struct ebt_u_entries *)
541 malloc(sizeof(struct ebt_u_entries));
542 if (!new)
543 print_memory();
544 u_repl->hook_entry[*hook] = new;
545 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000546 new->nentries = entries->nentries;
547 new->policy = entries->policy;
548 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000549 new->counter_offset = entries->counter_offset;
550 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000551 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000552 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000553}
554
Bart De Schuymer62423742002-07-14 19:06:20 +0000555static void retrieve_from_file(char *filename, struct ebt_replace *repl,
556 char command)
557{
558 FILE *file;
559 char *hlp;
560 int size;
561
562 if (!(file = fopen(filename, "r+b")))
563 print_error("Could not open file %s", filename);
564 // make sure table name is right if command isn't -L or --atomic-commit
565 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000566 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000567 if (!hlp)
568 print_memory();
569 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000570 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000571 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
572 != sizeof(struct ebt_replace))
573 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000574 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
575 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000576 print_error("File %s contains wrong table name or is corrupt",
577 filename);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000578 free(hlp);
579 } else if (!find_table(repl->name)) {
580 fclose(file);
581 print_error("File %s contains invalid table name", filename);
582 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000583
Bart De Schuymer62423742002-07-14 19:06:20 +0000584 size = sizeof(struct ebt_replace) +
585 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
586 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000587 if (size != ftell(file)) {
588 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000589 print_error("File %s has wrong size", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000590 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000591 repl->entries = (char *)malloc(repl->entries_size);
592 if (!repl->entries)
593 print_memory();
594 if (repl->nentries) {
595 repl->counters = (struct ebt_counter *)
596 malloc(repl->nentries * sizeof(struct ebt_counter));
597 if (!repl->counters)
598 print_memory();
599 } else
600 repl->counters = NULL;
601 // copy entries and counters
602 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
603 fread(repl->entries, sizeof(char), repl->entries_size, file)
604 != repl->entries_size ||
605 fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
606 || fread(repl->counters, sizeof(char),
607 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000608 != repl->nentries * sizeof(struct ebt_counter)) {
609 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000610 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000611 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000612 fclose(file);
613}
614
615static int retrieve_from_kernel(struct ebt_replace *repl, char command)
616{
617 socklen_t optlen;
618 int optname;
619
620 optlen = sizeof(struct ebt_replace);
621 get_sockfd();
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000622 // --atomic-init || --init-table
623 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000624 optname = EBT_SO_GET_INIT_INFO;
625 else
626 optname = EBT_SO_GET_INFO;
627 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
628 return -1;
629
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000630 if ( !(repl->entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer62423742002-07-14 19:06:20 +0000631 print_memory();
632 if (repl->nentries) {
633 if (!(repl->counters = (struct ebt_counter *)
634 malloc(repl->nentries * sizeof(struct ebt_counter))) )
635 print_memory();
636 }
637 else
638 repl->counters = NULL;
639
640 // we want to receive the counters
641 repl->num_counters = repl->nentries;
642 optlen += repl->entries_size + repl->num_counters *
643 sizeof(struct ebt_counter);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000644 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000645 optname = EBT_SO_GET_INIT_ENTRIES;
646 else
647 optname = EBT_SO_GET_ENTRIES;
648 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
649 print_bug("hmm, what is wrong??? bug#1");
650
651 return 0;
652}
653
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000654int get_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000655{
656 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000657 struct ebt_replace repl;
658 struct ebt_u_entry **u_e;
659
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000660 strcpy(repl.name, u_repl->name);
Bart De Schuymer62423742002-07-14 19:06:20 +0000661 if (u_repl->filename != NULL)
662 retrieve_from_file(u_repl->filename, &repl, u_repl->command);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000663 else if (retrieve_from_kernel(&repl, u_repl->command) == -1)
664 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000665
666 // translate the struct ebt_replace to a struct ebt_u_replace
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000667 u_repl->valid_hooks = repl.valid_hooks;
668 u_repl->nentries = repl.nentries;
669 u_repl->num_counters = repl.num_counters;
670 u_repl->counters = repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000671 u_repl->udc = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000672 hook = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000673 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
674 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000675 i = 0; // holds the expected nr. of entries for the chain
676 j = 0; // holds the up to now counted entries for the chain
677 k = 0; // holds the total nr. of entries,
678 // should equal u_repl->nentries afterwards
Bart De Schuymer60332e02002-06-23 08:01:47 +0000679 hook = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000680 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000681 &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks, repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000682 if (k != u_repl->nentries)
683 print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000684 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000685}
686
687void get_dbinfo(struct brdb_dbinfo *nr)
688{
689 socklen_t optlen = sizeof(struct brdb_dbinfo);
690
691 get_sockfd();
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000692
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000693 if (getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DBINFO, nr, &optlen))
694 print_error("Sorry, br_db code probably not in kernel, "
695 "try insmod br_db");
696}
697
698void get_db(int len, struct brdb_dbentry *db)
699{
700 socklen_t optlen = len;
701
702 get_sockfd();
703
704 if ( getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DB, db, &optlen) ) {
705 print_bug("hmm, what is wrong??? bug#2");
706 }
707}
708
709void deliver_allowdb(__u16 *decision)
710{
711 socklen_t optlen = sizeof(__u16);
712
713 get_sockfd();
714
715 if (setsockopt(sockfd, IPPROTO_IP, BRDB_SO_SET_ALLOWDB,
716 decision, optlen))
717 print_error("Sorry, br_db code probably not in kernel, "
718 "try insmod br_db");
719}