blob: 02db5001ae8b151a9f15a2a7625c6fa7ea504afb [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 Schuymer06b4fd22002-08-01 15:08:28 +000035 "you probably don't have the right "
36 "permissions");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000037 }
38}
39
40static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
41{
42 struct ebt_replace *new;
43 struct ebt_u_entry *e;
44 struct ebt_u_match_list *m_l;
45 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +000046 struct ebt_u_chain_list *cl;
47 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000048 char *p, *base;
49 int i, j;
Bart De Schuymer60332e02002-06-23 08:01:47 +000050 unsigned int entries_size = 0, *chain_offsets;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000051
52 new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
53 if (!new)
54 print_memory();
55 new->valid_hooks = u_repl->valid_hooks;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000056 strcpy(new->name, u_repl->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000057 new->nentries = u_repl->nentries;
58 new->num_counters = u_repl->num_counters;
59 new->counters = u_repl->counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +000060 // determine nr of udc
61 i = 0;
62 cl = u_repl->udc;
63 while (cl) {
64 i++;
65 cl = cl->next;
66 }
67 i += NF_BR_NUMHOOKS;
68 chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000069 // determine size
Bart De Schuymer60332e02002-06-23 08:01:47 +000070 i = 0;
71 cl = u_repl->udc;
72 while (1) {
73 if (i < NF_BR_NUMHOOKS) {
74 if (!(new->valid_hooks & (1 << i))) {
75 i++;
76 continue;
77 }
78 entries = u_repl->hook_entry[i];
79 } else {
80 if (!cl)
81 break;
82 entries = cl->udc;
83 }
84 chain_offsets[i] = entries_size;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000085 entries_size += sizeof(struct ebt_entries);
86 j = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +000087 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000088 while (e) {
89 j++;
90 entries_size += sizeof(struct ebt_entry);
91 m_l = e->m_list;
92 while (m_l) {
93 entries_size += m_l->m->match_size +
94 sizeof(struct ebt_entry_match);
95 m_l = m_l->next;
96 }
97 w_l = e->w_list;
98 while (w_l) {
99 entries_size += w_l->w->watcher_size +
100 sizeof(struct ebt_entry_watcher);
101 w_l = w_l->next;
102 }
103 entries_size += e->t->target_size +
104 sizeof(struct ebt_entry_target);
105 e = e->next;
106 }
107 // a little sanity check
Bart De Schuymer60332e02002-06-23 08:01:47 +0000108 if (j != entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000109 print_bug("Wrong nentries: %d != %d, hook = %s", j,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000110 entries->nentries, entries->name);
111 if (i >= NF_BR_NUMHOOKS)
112 cl = cl->next;
113 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000114 }
115
116 new->entries_size = entries_size;
117 new->entries = (char *)malloc(entries_size);
118 if (!new->entries)
119 print_memory();
120
121 // put everything in one block
122 p = new->entries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000123 i = 0;
124 cl = u_repl->udc;
125 while (1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000126 struct ebt_entries *hlp;
127
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000128 hlp = (struct ebt_entries *)p;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000129 if (i < NF_BR_NUMHOOKS) {
130 if (!(new->valid_hooks & (1 << i))) {
131 i++;
132 continue;
133 }
134 entries = u_repl->hook_entry[i];
135 new->hook_entry[i] = hlp;
136 } else {
137 if (!cl)
138 break;
139 entries = cl->udc;
140 }
141 hlp->nentries = entries->nentries;
142 hlp->policy = entries->policy;
143 strcpy(hlp->name, entries->name);
144 hlp->counter_offset = entries->counter_offset;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000145 hlp->distinguisher = 0; // make the kernel see the light
146 p += sizeof(struct ebt_entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000147 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000148 while (e) {
149 struct ebt_entry *tmp = (struct ebt_entry *)p;
150
151 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
152 tmp->invflags = e->invflags;
153 tmp->ethproto = e->ethproto;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000154 strcpy(tmp->in, e->in);
155 strcpy(tmp->out, e->out);
156 strcpy(tmp->logical_in, e->logical_in);
157 strcpy(tmp->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000158 memcpy(tmp->sourcemac, e->sourcemac,
159 sizeof(tmp->sourcemac));
160 memcpy(tmp->sourcemsk, e->sourcemsk,
161 sizeof(tmp->sourcemsk));
162 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
163 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
164
165 base = p;
166 p += sizeof(struct ebt_entry);
167 m_l = e->m_list;
168 while (m_l) {
169 memcpy(p, m_l->m, m_l->m->match_size +
170 sizeof(struct ebt_entry_match));
171 p += m_l->m->match_size +
172 sizeof(struct ebt_entry_match);
173 m_l = m_l->next;
174 }
175 tmp->watchers_offset = p - base;
176 w_l = e->w_list;
177 while (w_l) {
178 memcpy(p, w_l->w, w_l->w->watcher_size +
179 sizeof(struct ebt_entry_watcher));
180 p += w_l->w->watcher_size +
181 sizeof(struct ebt_entry_watcher);
182 w_l = w_l->next;
183 }
184 tmp->target_offset = p - base;
185 memcpy(p, e->t, e->t->target_size +
186 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000187 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
188 struct ebt_standard_target *st =
189 (struct ebt_standard_target *)p;
190 // translate the jump to a udc
191 if (st->verdict >= 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000192 st->verdict = chain_offsets
193 [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 Schuymer62423742002-07-14 19:06:20 +0000260 if (u_repl->filename != NULL) {
261 store_table_in_file(u_repl->filename, repl);
262 return;
263 }
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000264 // give the data to the kernel
265 optlen = sizeof(struct ebt_replace) + repl->entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000266 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"
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000270 " 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);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000276 unsigned int entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000277 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++;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000327 } else if (*point == CNT_DEL) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000328 // 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 {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000334 // zero it (let it stay 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000335 old++;
336 new++;
337 }
338 point++;
339 }
340
341 free(u_repl->counters);
342 u_repl->counters = newcounters;
343 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000344 if (u_repl->filename != NULL) {
345 store_counters_in_file(u_repl->filename, u_repl);
346 return;
347 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000348 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
349 sizeof(struct ebt_replace);
350 // now put the stuff in the kernel's struct ebt_replace
351 repl.counters = u_repl->counters;
352 repl.num_counters = u_repl->num_counters;
353 memcpy(repl.name, u_repl->name, sizeof(repl.name));
354
355 get_sockfd();
356 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000357 print_bug("Couldn't update kernel counters");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000358}
359
360static int
361ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
362{
363 struct ebt_u_match_list *new;
364
365 new = (struct ebt_u_match_list *)
366 malloc(sizeof(struct ebt_u_match_list));
367 if (!new)
368 print_memory();
369 new->m = (struct ebt_entry_match *)
370 malloc(m->match_size + sizeof(struct ebt_entry_match));
371 if (!new->m)
372 print_memory();
373 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
374 new->next = NULL;
375 **l = new;
376 *l = &new->next;
377 if (find_match(new->m->u.name) == NULL)
378 print_error("Kernel match %s unsupported by userspace tool",
379 new->m->u.name);
380 return 0;
381}
382
383static int
384ebt_translate_watcher(struct ebt_entry_watcher *w,
385 struct ebt_u_watcher_list ***l)
386{
387 struct ebt_u_watcher_list *new;
388
389 new = (struct ebt_u_watcher_list *)
390 malloc(sizeof(struct ebt_u_watcher_list));
391 if (!new)
392 print_memory();
393 new->w = (struct ebt_entry_watcher *)
394 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
395 if (!new->w)
396 print_memory();
397 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
398 new->next = NULL;
399 **l = new;
400 *l = &new->next;
401 if (find_watcher(new->w->u.name) == NULL)
402 print_error("Kernel watcher %s unsupported by userspace tool",
403 new->w->u.name);
404 return 0;
405}
406
407static int
408ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
409 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000410 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000411{
412 // an entry
413 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
414 struct ebt_u_entry *new;
415 struct ebt_u_match_list **m_l;
416 struct ebt_u_watcher_list **w_l;
417 struct ebt_entry_target *t;
418
419 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
420 if (!new)
421 print_memory();
422 new->bitmask = e->bitmask;
423 // plain userspace code doesn't know about EBT_ENTRY_OR_ENTRIES
424 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
425 new->invflags = e->invflags;
426 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000427 strcpy(new->in, e->in);
428 strcpy(new->out, e->out);
429 strcpy(new->logical_in, e->logical_in);
430 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000431 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
432 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
433 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
434 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
435 new->m_list = NULL;
436 new->w_list = NULL;
437 new->next = NULL;
438 m_l = &new->m_list;
439 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
440 w_l = &new->w_list;
441 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
442
443 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
444 new->t = (struct ebt_entry_target *)
445 malloc(t->target_size + sizeof(struct ebt_entry_target));
446 if (!new->t)
447 print_memory();
448 if (find_target(t->u.name) == NULL)
449 print_error("Kernel target %s unsupported by "
450 "userspace tool", t->u.name);
451 memcpy(new->t, t, t->target_size +
452 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000453 // deal with jumps to udc
454 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
455 char *tmp = base;
456 int verdict = ((struct ebt_standard_target *)t)->verdict;
457 int i;
458 struct ebt_u_chain_list *cl;
459
460 if (verdict >= 0) {
461 tmp += verdict;
462 cl = u_repl->udc;
463 i = 0;
464 while (cl && cl->kernel_start != tmp) {
465 i++;
466 cl = cl->next;
467 }
468 if (!cl)
469 print_bug("can't find udc for jump");
470 ((struct ebt_standard_target *)new->t)->verdict = i;
471 }
472 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000473
474 // I love pointers
475 **u_e = new;
476 *u_e = &new->next;
477 (*cnt)++;
478 (*totalcnt)++;
479 return 0;
480 } else { // a new chain
481 int i;
482 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000483 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000484
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000485 if (*n != *cnt)
486 print_bug("Nr of entries in the chain is wrong");
487 *n = entries->nentries;
488 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000489 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
490 if (valid_hooks & (1 << i))
491 break;
492 *hook = i;
493 // makes use of fact that standard chains come before udc
494 if (i >= NF_BR_NUMHOOKS) { // udc
495 i -= NF_BR_NUMHOOKS;
496 cl = u_repl->udc;
497 while (i-- > 0)
498 cl = cl->next;
499 *u_e = &(cl->udc->entries);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000500 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000501 *u_e = &(u_repl->hook_entry[*hook]->entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000502 return 0;
503 }
504}
505
506// initialize all chain headers
507static int
508ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
509 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
510{
511 int i;
512 struct ebt_entries *entries = (struct ebt_entries *)e;
513 struct ebt_u_entries *new;
514 struct ebt_u_chain_list **chain_list;
515
516 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
517 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
518 if (valid_hooks & (1 << i))
519 break;
520 // makes use of fact that standard chains come before udc
521 if (i >= NF_BR_NUMHOOKS) { // udc
522 chain_list = &u_repl->udc;
523 // add in the back
524 while (*chain_list)
525 chain_list = &((*chain_list)->next);
526 *chain_list = (struct ebt_u_chain_list *)
527 malloc(sizeof(struct ebt_u_chain_list));
528 if (!(*chain_list))
529 print_memory();
530 (*chain_list)->next = NULL;
531 (*chain_list)->udc = (struct ebt_u_entries *)
532 malloc(sizeof(struct ebt_u_entries));
533 if (!((*chain_list)->udc))
534 print_memory();
535 new = (*chain_list)->udc;
536 // ebt_translate_entry depends on this for knowing
537 // to which chain is being jumped
538 (*chain_list)->kernel_start = (char *)e;
539 } else {
540 *hook = i;
541 new = (struct ebt_u_entries *)
542 malloc(sizeof(struct ebt_u_entries));
543 if (!new)
544 print_memory();
545 u_repl->hook_entry[*hook] = new;
546 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000547 new->nentries = entries->nentries;
548 new->policy = entries->policy;
549 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000550 new->counter_offset = entries->counter_offset;
551 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000552 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000553 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000554}
555
Bart De Schuymer62423742002-07-14 19:06:20 +0000556static void retrieve_from_file(char *filename, struct ebt_replace *repl,
557 char command)
558{
559 FILE *file;
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000560 char *hlp = NULL;
Bart De Schuymer62423742002-07-14 19:06:20 +0000561 int size;
562
563 if (!(file = fopen(filename, "r+b")))
564 print_error("Could not open file %s", filename);
565 // make sure table name is right if command isn't -L or --atomic-commit
566 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000567 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000568 if (!hlp)
569 print_memory();
570 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000571 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000572 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
573 != sizeof(struct ebt_replace))
574 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000575 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
576 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000577 print_error("File %s contains wrong table name or is corrupt",
578 filename);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000579 free(hlp);
580 } else if (!find_table(repl->name)) {
581 fclose(file);
582 print_error("File %s contains invalid table name", filename);
583 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000584
Bart De Schuymer62423742002-07-14 19:06:20 +0000585 size = sizeof(struct ebt_replace) +
586 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
587 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000588 if (size != ftell(file)) {
589 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000590 print_error("File %s has wrong size", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000591 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000592 repl->entries = (char *)malloc(repl->entries_size);
593 if (!repl->entries)
594 print_memory();
595 if (repl->nentries) {
596 repl->counters = (struct ebt_counter *)
597 malloc(repl->nentries * sizeof(struct ebt_counter));
598 if (!repl->counters)
599 print_memory();
600 } else
601 repl->counters = NULL;
602 // copy entries and counters
603 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
604 fread(repl->entries, sizeof(char), repl->entries_size, file)
605 != repl->entries_size ||
606 fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
607 || fread(repl->counters, sizeof(char),
608 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000609 != repl->nentries * sizeof(struct ebt_counter)) {
610 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000611 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000612 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000613 fclose(file);
614}
615
616static int retrieve_from_kernel(struct ebt_replace *repl, char command)
617{
618 socklen_t optlen;
619 int optname;
620
621 optlen = sizeof(struct ebt_replace);
622 get_sockfd();
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000623 // --atomic-init || --init-table
624 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000625 optname = EBT_SO_GET_INIT_INFO;
626 else
627 optname = EBT_SO_GET_INFO;
628 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
629 return -1;
630
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000631 if ( !(repl->entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer62423742002-07-14 19:06:20 +0000632 print_memory();
633 if (repl->nentries) {
634 if (!(repl->counters = (struct ebt_counter *)
635 malloc(repl->nentries * sizeof(struct ebt_counter))) )
636 print_memory();
637 }
638 else
639 repl->counters = NULL;
640
641 // we want to receive the counters
642 repl->num_counters = repl->nentries;
643 optlen += repl->entries_size + repl->num_counters *
644 sizeof(struct ebt_counter);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000645 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000646 optname = EBT_SO_GET_INIT_ENTRIES;
647 else
648 optname = EBT_SO_GET_ENTRIES;
649 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
650 print_bug("hmm, what is wrong??? bug#1");
651
652 return 0;
653}
654
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000655int get_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000656{
657 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000658 struct ebt_replace repl;
659 struct ebt_u_entry **u_e;
660
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000661 strcpy(repl.name, u_repl->name);
Bart De Schuymer62423742002-07-14 19:06:20 +0000662 if (u_repl->filename != NULL)
663 retrieve_from_file(u_repl->filename, &repl, u_repl->command);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000664 else if (retrieve_from_kernel(&repl, u_repl->command) == -1)
665 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000666
667 // translate the struct ebt_replace to a struct ebt_u_replace
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000668 u_repl->valid_hooks = repl.valid_hooks;
669 u_repl->nentries = repl.nentries;
670 u_repl->num_counters = repl.num_counters;
671 u_repl->counters = repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000672 u_repl->udc = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000673 hook = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000674 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
675 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000676 i = 0; // holds the expected nr. of entries for the chain
677 j = 0; // holds the up to now counted entries for the chain
678 k = 0; // holds the total nr. of entries,
679 // should equal u_repl->nentries afterwards
Bart De Schuymer60332e02002-06-23 08:01:47 +0000680 hook = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000681 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000682 &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks, repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000683 if (k != u_repl->nentries)
684 print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000685 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000686}
687
688void get_dbinfo(struct brdb_dbinfo *nr)
689{
690 socklen_t optlen = sizeof(struct brdb_dbinfo);
691
692 get_sockfd();
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000693
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000694 if (getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DBINFO, nr, &optlen))
695 print_error("Sorry, br_db code probably not in kernel, "
696 "try insmod br_db");
697}
698
699void get_db(int len, struct brdb_dbentry *db)
700{
701 socklen_t optlen = len;
702
703 get_sockfd();
704
705 if ( getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DB, db, &optlen) ) {
706 print_bug("hmm, what is wrong??? bug#2");
707 }
708}
709
710void deliver_allowdb(__u16 *decision)
711{
712 socklen_t optlen = sizeof(__u16);
713
714 get_sockfd();
715
716 if (setsockopt(sockfd, IPPROTO_IP, BRDB_SO_SET_ALLOWDB,
717 decision, optlen))
718 print_error("Sorry, br_db code probably not in kernel, "
719 "try insmod br_db");
720}