blob: 1bc14e7ef69344a9aa025acb8fc52f27a3a07b3f [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 Schuymer1abc55d2002-06-01 19:23:47 +000021#include "include/ebtables_u.h"
22
23extern char* hooknames[NF_BR_NUMHOOKS];
24
25int sockfd = -1;
26
Bart De Schuymer62423742002-07-14 19:06:20 +000027static void get_sockfd()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000028{
29 if (sockfd == -1) {
30 sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
31 if (sockfd < 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000032 print_error("Problem getting a socket, "
Bart De Schuymer06b4fd22002-08-01 15:08:28 +000033 "you probably don't have the right "
34 "permissions");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035 }
36}
37
38static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
39{
40 struct ebt_replace *new;
41 struct ebt_u_entry *e;
42 struct ebt_u_match_list *m_l;
43 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +000044 struct ebt_u_chain_list *cl;
45 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000046 char *p, *base;
47 int i, j;
Bart De Schuymer60332e02002-06-23 08:01:47 +000048 unsigned int entries_size = 0, *chain_offsets;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000049
50 new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
51 if (!new)
52 print_memory();
53 new->valid_hooks = u_repl->valid_hooks;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000054 strcpy(new->name, u_repl->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000055 new->nentries = u_repl->nentries;
56 new->num_counters = u_repl->num_counters;
57 new->counters = u_repl->counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +000058 // determine nr of udc
59 i = 0;
60 cl = u_repl->udc;
61 while (cl) {
62 i++;
63 cl = cl->next;
64 }
65 i += NF_BR_NUMHOOKS;
66 chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000067 // determine size
Bart De Schuymer60332e02002-06-23 08:01:47 +000068 i = 0;
69 cl = u_repl->udc;
70 while (1) {
71 if (i < NF_BR_NUMHOOKS) {
72 if (!(new->valid_hooks & (1 << i))) {
73 i++;
74 continue;
75 }
76 entries = u_repl->hook_entry[i];
77 } else {
78 if (!cl)
79 break;
80 entries = cl->udc;
81 }
82 chain_offsets[i] = entries_size;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000083 entries_size += sizeof(struct ebt_entries);
84 j = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +000085 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000086 while (e) {
87 j++;
88 entries_size += sizeof(struct ebt_entry);
89 m_l = e->m_list;
90 while (m_l) {
91 entries_size += m_l->m->match_size +
92 sizeof(struct ebt_entry_match);
93 m_l = m_l->next;
94 }
95 w_l = e->w_list;
96 while (w_l) {
97 entries_size += w_l->w->watcher_size +
98 sizeof(struct ebt_entry_watcher);
99 w_l = w_l->next;
100 }
101 entries_size += e->t->target_size +
102 sizeof(struct ebt_entry_target);
103 e = e->next;
104 }
105 // a little sanity check
Bart De Schuymer60332e02002-06-23 08:01:47 +0000106 if (j != entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000107 print_bug("Wrong nentries: %d != %d, hook = %s", j,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000108 entries->nentries, entries->name);
109 if (i >= NF_BR_NUMHOOKS)
110 cl = cl->next;
111 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000112 }
113
114 new->entries_size = entries_size;
115 new->entries = (char *)malloc(entries_size);
116 if (!new->entries)
117 print_memory();
118
119 // put everything in one block
120 p = new->entries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000121 i = 0;
122 cl = u_repl->udc;
123 while (1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000124 struct ebt_entries *hlp;
125
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000126 hlp = (struct ebt_entries *)p;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000127 if (i < NF_BR_NUMHOOKS) {
128 if (!(new->valid_hooks & (1 << i))) {
129 i++;
130 continue;
131 }
132 entries = u_repl->hook_entry[i];
133 new->hook_entry[i] = hlp;
134 } else {
135 if (!cl)
136 break;
137 entries = cl->udc;
138 }
139 hlp->nentries = entries->nentries;
140 hlp->policy = entries->policy;
141 strcpy(hlp->name, entries->name);
142 hlp->counter_offset = entries->counter_offset;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000143 hlp->distinguisher = 0; // make the kernel see the light
144 p += sizeof(struct ebt_entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000145 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000146 while (e) {
147 struct ebt_entry *tmp = (struct ebt_entry *)p;
148
149 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
150 tmp->invflags = e->invflags;
151 tmp->ethproto = e->ethproto;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000152 strcpy(tmp->in, e->in);
153 strcpy(tmp->out, e->out);
154 strcpy(tmp->logical_in, e->logical_in);
155 strcpy(tmp->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000156 memcpy(tmp->sourcemac, e->sourcemac,
157 sizeof(tmp->sourcemac));
158 memcpy(tmp->sourcemsk, e->sourcemsk,
159 sizeof(tmp->sourcemsk));
160 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
161 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
162
163 base = p;
164 p += sizeof(struct ebt_entry);
165 m_l = e->m_list;
166 while (m_l) {
167 memcpy(p, m_l->m, m_l->m->match_size +
168 sizeof(struct ebt_entry_match));
169 p += m_l->m->match_size +
170 sizeof(struct ebt_entry_match);
171 m_l = m_l->next;
172 }
173 tmp->watchers_offset = p - base;
174 w_l = e->w_list;
175 while (w_l) {
176 memcpy(p, w_l->w, w_l->w->watcher_size +
177 sizeof(struct ebt_entry_watcher));
178 p += w_l->w->watcher_size +
179 sizeof(struct ebt_entry_watcher);
180 w_l = w_l->next;
181 }
182 tmp->target_offset = p - base;
183 memcpy(p, e->t, e->t->target_size +
184 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000185 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
186 struct ebt_standard_target *st =
187 (struct ebt_standard_target *)p;
188 // translate the jump to a udc
189 if (st->verdict >= 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000190 st->verdict = chain_offsets
191 [st->verdict + NF_BR_NUMHOOKS];
Bart De Schuymer60332e02002-06-23 08:01:47 +0000192 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000193 p += e->t->target_size +
194 sizeof(struct ebt_entry_target);
195 tmp->next_offset = p - base;
196 e = e->next;
197 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000198 if (i >= NF_BR_NUMHOOKS)
199 cl = cl->next;
200 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000201 }
202
203 // sanity check
204 if (p - new->entries != new->entries_size)
205 print_bug("Entries_size bug");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000206 free(chain_offsets);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000207 return new;
208}
209
Bart De Schuymer62423742002-07-14 19:06:20 +0000210static void store_table_in_file(char *filename, struct ebt_replace *repl)
211{
212 char *command, *data;
213 int size;
214 FILE *file;
215
216 // start from an empty file with right priviliges
217 command = (char *)malloc(strlen(filename) + 15);
218 if (!command)
219 print_memory();
220 strcpy(command, "cat /dev/null>");
221 strcpy(command + 14, filename);
222 if (system(command))
223 print_error("Couldn't create file %s", filename);
224 strcpy(command, "chmod 600 ");
225 strcpy(command + 10, filename);
226 if (system(command))
227 print_error("Couldn't chmod file %s", filename);
228 free(command);
229
230 size = sizeof(struct ebt_replace) + repl->entries_size +
231 repl->nentries * sizeof(struct ebt_counter);
232 data = (char *)malloc(size);
233 if (!data)
234 print_memory();
235 memcpy(data, repl, sizeof(struct ebt_replace));
236 memcpy(data + sizeof(struct ebt_replace), repl->entries,
237 repl->entries_size);
238 // initialize counters to zero, deliver_counters() can update them
239 memset(data + sizeof(struct ebt_replace) + repl->entries_size,
240 0, repl->nentries * sizeof(struct ebt_counter));
241 if (!(file = fopen(filename, "wb")))
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000242 print_error("Couldn't open file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000243 if (fwrite(data, sizeof(char), size, file) != size) {
244 fclose(file);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000245 print_error("Couldn't write everything to file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000246 }
247 fclose(file);
248 free(data);
249}
250
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000251void deliver_table(struct ebt_u_replace *u_repl)
252{
253 socklen_t optlen;
254 struct ebt_replace *repl;
255
256 // translate the struct ebt_u_replace to a struct ebt_replace
257 repl = translate_user2kernel(u_repl);
Bart De Schuymer62423742002-07-14 19:06:20 +0000258 if (u_repl->filename != NULL) {
259 store_table_in_file(u_repl->filename, repl);
260 return;
261 }
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000262 // give the data to the kernel
263 optlen = sizeof(struct ebt_replace) + repl->entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000264 get_sockfd();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000265 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
Bart De Schuymer73564dc2002-06-05 18:13:51 +0000266 print_error("The kernel doesn't support a certain ebtables"
267 " extension, consider recompiling your kernel or insmod"
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000268 " the extension");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000269}
270
Bart De Schuymer62423742002-07-14 19:06:20 +0000271static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
272{
273 int size = repl->nentries * sizeof(struct ebt_counter);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000274 unsigned int entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000275 struct ebt_replace hlp;
276 FILE *file;
277
278 if (!(file = fopen(filename, "r+b")))
279 print_error("Could not open file %s", filename);
280 // find out entries_size and then set the file pointer to the counters
281 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
282 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
283 sizeof(unsigned int) ||
284 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
285 fclose(file);
286 print_error("File %s is corrupt", filename);
287 }
288 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
289 fclose(file);
290 print_error("Could not write everything to file %s", filename);
291 }
292 fclose(file);
293}
294
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000295// gets executed after deliver_table
296void
Bart De Schuymered053432002-07-21 19:35:39 +0000297deliver_counters(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000298{
299 unsigned short *point;
300 struct ebt_counter *old, *new, *newcounters;
301 socklen_t optlen;
302 struct ebt_replace repl;
Bart De Schuymered053432002-07-21 19:35:39 +0000303 unsigned short *counterchanges = u_repl->counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000304
305 if (u_repl->nentries == 0)
306 return;
307
308 newcounters = (struct ebt_counter *)
309 malloc(u_repl->nentries * sizeof(struct ebt_counter));
310 if (!newcounters)
311 print_memory();
312 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
313 old = u_repl->counters;
314 new = newcounters;
315 point = counterchanges;
316 while (*point != CNT_END) {
317 if (*point == CNT_NORM) {
318 // 'normal' rule, meaning we didn't do anything to it
319 // So, we just copy
320 new->pcnt = old->pcnt;
321 // we've used an old counter
322 old++;
323 // we've set a new counter
324 new++;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000325 } else if (*point == CNT_DEL) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000326 // don't use this old counter
327 old++;
328 } else if (*point == CNT_ADD) {
329 // new counter, let it stay 0
330 new++;
331 } else {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000332 // zero it (let it stay 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000333 old++;
334 new++;
335 }
336 point++;
337 }
338
339 free(u_repl->counters);
340 u_repl->counters = newcounters;
341 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000342 if (u_repl->filename != NULL) {
343 store_counters_in_file(u_repl->filename, u_repl);
344 return;
345 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000346 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
347 sizeof(struct ebt_replace);
348 // now put the stuff in the kernel's struct ebt_replace
349 repl.counters = u_repl->counters;
350 repl.num_counters = u_repl->num_counters;
351 memcpy(repl.name, u_repl->name, sizeof(repl.name));
352
353 get_sockfd();
354 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000355 print_bug("Couldn't update kernel counters");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000356}
357
358static int
359ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
360{
361 struct ebt_u_match_list *new;
362
363 new = (struct ebt_u_match_list *)
364 malloc(sizeof(struct ebt_u_match_list));
365 if (!new)
366 print_memory();
367 new->m = (struct ebt_entry_match *)
368 malloc(m->match_size + sizeof(struct ebt_entry_match));
369 if (!new->m)
370 print_memory();
371 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
372 new->next = NULL;
373 **l = new;
374 *l = &new->next;
375 if (find_match(new->m->u.name) == NULL)
376 print_error("Kernel match %s unsupported by userspace tool",
377 new->m->u.name);
378 return 0;
379}
380
381static int
382ebt_translate_watcher(struct ebt_entry_watcher *w,
383 struct ebt_u_watcher_list ***l)
384{
385 struct ebt_u_watcher_list *new;
386
387 new = (struct ebt_u_watcher_list *)
388 malloc(sizeof(struct ebt_u_watcher_list));
389 if (!new)
390 print_memory();
391 new->w = (struct ebt_entry_watcher *)
392 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
393 if (!new->w)
394 print_memory();
395 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
396 new->next = NULL;
397 **l = new;
398 *l = &new->next;
399 if (find_watcher(new->w->u.name) == NULL)
400 print_error("Kernel watcher %s unsupported by userspace tool",
401 new->w->u.name);
402 return 0;
403}
404
405static int
406ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
407 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000408 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000409{
410 // an entry
411 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
412 struct ebt_u_entry *new;
413 struct ebt_u_match_list **m_l;
414 struct ebt_u_watcher_list **w_l;
415 struct ebt_entry_target *t;
416
417 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
418 if (!new)
419 print_memory();
420 new->bitmask = e->bitmask;
421 // plain userspace code doesn't know about EBT_ENTRY_OR_ENTRIES
422 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
423 new->invflags = e->invflags;
424 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000425 strcpy(new->in, e->in);
426 strcpy(new->out, e->out);
427 strcpy(new->logical_in, e->logical_in);
428 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000429 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
430 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
431 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
432 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
433 new->m_list = NULL;
434 new->w_list = NULL;
435 new->next = NULL;
436 m_l = &new->m_list;
437 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
438 w_l = &new->w_list;
439 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
440
441 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
442 new->t = (struct ebt_entry_target *)
443 malloc(t->target_size + sizeof(struct ebt_entry_target));
444 if (!new->t)
445 print_memory();
446 if (find_target(t->u.name) == NULL)
447 print_error("Kernel target %s unsupported by "
448 "userspace tool", t->u.name);
449 memcpy(new->t, t, t->target_size +
450 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000451 // deal with jumps to udc
452 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
453 char *tmp = base;
454 int verdict = ((struct ebt_standard_target *)t)->verdict;
455 int i;
456 struct ebt_u_chain_list *cl;
457
458 if (verdict >= 0) {
459 tmp += verdict;
460 cl = u_repl->udc;
461 i = 0;
462 while (cl && cl->kernel_start != tmp) {
463 i++;
464 cl = cl->next;
465 }
466 if (!cl)
467 print_bug("can't find udc for jump");
468 ((struct ebt_standard_target *)new->t)->verdict = i;
469 }
470 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000471
472 // I love pointers
473 **u_e = new;
474 *u_e = &new->next;
475 (*cnt)++;
476 (*totalcnt)++;
477 return 0;
478 } else { // a new chain
479 int i;
480 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000481 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000482
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000483 if (*n != *cnt)
484 print_bug("Nr of entries in the chain is wrong");
485 *n = entries->nentries;
486 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000487 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
488 if (valid_hooks & (1 << i))
489 break;
490 *hook = i;
491 // makes use of fact that standard chains come before udc
492 if (i >= NF_BR_NUMHOOKS) { // udc
493 i -= NF_BR_NUMHOOKS;
494 cl = u_repl->udc;
495 while (i-- > 0)
496 cl = cl->next;
497 *u_e = &(cl->udc->entries);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000498 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000499 *u_e = &(u_repl->hook_entry[*hook]->entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000500 return 0;
501 }
502}
503
504// initialize all chain headers
505static int
506ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
507 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
508{
509 int i;
510 struct ebt_entries *entries = (struct ebt_entries *)e;
511 struct ebt_u_entries *new;
512 struct ebt_u_chain_list **chain_list;
513
514 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
515 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
516 if (valid_hooks & (1 << i))
517 break;
518 // makes use of fact that standard chains come before udc
519 if (i >= NF_BR_NUMHOOKS) { // udc
520 chain_list = &u_repl->udc;
521 // add in the back
522 while (*chain_list)
523 chain_list = &((*chain_list)->next);
524 *chain_list = (struct ebt_u_chain_list *)
525 malloc(sizeof(struct ebt_u_chain_list));
526 if (!(*chain_list))
527 print_memory();
528 (*chain_list)->next = NULL;
529 (*chain_list)->udc = (struct ebt_u_entries *)
530 malloc(sizeof(struct ebt_u_entries));
531 if (!((*chain_list)->udc))
532 print_memory();
533 new = (*chain_list)->udc;
534 // ebt_translate_entry depends on this for knowing
535 // to which chain is being jumped
536 (*chain_list)->kernel_start = (char *)e;
537 } else {
538 *hook = i;
539 new = (struct ebt_u_entries *)
540 malloc(sizeof(struct ebt_u_entries));
541 if (!new)
542 print_memory();
543 u_repl->hook_entry[*hook] = new;
544 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000545 new->nentries = entries->nentries;
546 new->policy = entries->policy;
547 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000548 new->counter_offset = entries->counter_offset;
549 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000550 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000551 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000552}
553
Bart De Schuymer62423742002-07-14 19:06:20 +0000554static void retrieve_from_file(char *filename, struct ebt_replace *repl,
555 char command)
556{
557 FILE *file;
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000558 char *hlp = NULL;
Bart De Schuymer62423742002-07-14 19:06:20 +0000559 int size;
560
561 if (!(file = fopen(filename, "r+b")))
562 print_error("Could not open file %s", filename);
563 // make sure table name is right if command isn't -L or --atomic-commit
564 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000565 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000566 if (!hlp)
567 print_memory();
568 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000569 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000570 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
571 != sizeof(struct ebt_replace))
572 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000573 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
574 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000575 print_error("File %s contains wrong table name or is corrupt",
576 filename);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000577 free(hlp);
578 } else if (!find_table(repl->name)) {
579 fclose(file);
580 print_error("File %s contains invalid table name", filename);
581 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000582
Bart De Schuymer62423742002-07-14 19:06:20 +0000583 size = sizeof(struct ebt_replace) +
584 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
585 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000586 if (size != ftell(file)) {
587 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000588 print_error("File %s has wrong size", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000589 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000590 repl->entries = (char *)malloc(repl->entries_size);
591 if (!repl->entries)
592 print_memory();
593 if (repl->nentries) {
594 repl->counters = (struct ebt_counter *)
595 malloc(repl->nentries * sizeof(struct ebt_counter));
596 if (!repl->counters)
597 print_memory();
598 } else
599 repl->counters = NULL;
600 // copy entries and counters
601 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
602 fread(repl->entries, sizeof(char), repl->entries_size, file)
603 != repl->entries_size ||
604 fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
605 || fread(repl->counters, sizeof(char),
606 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000607 != repl->nentries * sizeof(struct ebt_counter)) {
608 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000609 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000610 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000611 fclose(file);
612}
613
614static int retrieve_from_kernel(struct ebt_replace *repl, char command)
615{
616 socklen_t optlen;
617 int optname;
618
619 optlen = sizeof(struct ebt_replace);
620 get_sockfd();
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000621 // --atomic-init || --init-table
622 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000623 optname = EBT_SO_GET_INIT_INFO;
624 else
625 optname = EBT_SO_GET_INFO;
626 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
627 return -1;
628
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000629 if ( !(repl->entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer62423742002-07-14 19:06:20 +0000630 print_memory();
631 if (repl->nentries) {
632 if (!(repl->counters = (struct ebt_counter *)
633 malloc(repl->nentries * sizeof(struct ebt_counter))) )
634 print_memory();
635 }
636 else
637 repl->counters = NULL;
638
639 // we want to receive the counters
640 repl->num_counters = repl->nentries;
641 optlen += repl->entries_size + repl->num_counters *
642 sizeof(struct ebt_counter);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000643 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000644 optname = EBT_SO_GET_INIT_ENTRIES;
645 else
646 optname = EBT_SO_GET_ENTRIES;
647 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
648 print_bug("hmm, what is wrong??? bug#1");
649
650 return 0;
651}
652
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000653int get_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000654{
655 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000656 struct ebt_replace repl;
657 struct ebt_u_entry **u_e;
658
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000659 strcpy(repl.name, u_repl->name);
Bart De Schuymer62423742002-07-14 19:06:20 +0000660 if (u_repl->filename != NULL)
661 retrieve_from_file(u_repl->filename, &repl, u_repl->command);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000662 else if (retrieve_from_kernel(&repl, u_repl->command) == -1)
663 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000664
665 // translate the struct ebt_replace to a struct ebt_u_replace
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000666 u_repl->valid_hooks = repl.valid_hooks;
667 u_repl->nentries = repl.nentries;
668 u_repl->num_counters = repl.num_counters;
669 u_repl->counters = repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000670 u_repl->udc = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000671 hook = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000672 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
673 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000674 i = 0; // holds the expected nr. of entries for the chain
675 j = 0; // holds the up to now counted entries for the chain
676 k = 0; // holds the total nr. of entries,
677 // should equal u_repl->nentries afterwards
Bart De Schuymer60332e02002-06-23 08:01:47 +0000678 hook = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000679 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000680 &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks, repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000681 if (k != u_repl->nentries)
682 print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000683 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000684}