blob: 887ee0861b51e7e1249c6f508bbb5cfc1371d3dc [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>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000020#include "include/ebtables_u.h"
21
22extern char* hooknames[NF_BR_NUMHOOKS];
23
24int sockfd = -1;
25
Bart De Schuymer62423742002-07-14 19:06:20 +000026static void get_sockfd()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000027{
28 if (sockfd == -1) {
29 sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
30 if (sockfd < 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000031 print_error("Problem getting a socket, "
Bart De Schuymer06b4fd22002-08-01 15:08:28 +000032 "you probably don't have the right "
33 "permissions");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000034 }
35}
36
37static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
38{
39 struct ebt_replace *new;
40 struct ebt_u_entry *e;
41 struct ebt_u_match_list *m_l;
42 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +000043 struct ebt_u_chain_list *cl;
44 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000045 char *p, *base;
46 int i, j;
Bart De Schuymer60332e02002-06-23 08:01:47 +000047 unsigned int entries_size = 0, *chain_offsets;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000048
49 new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
50 if (!new)
51 print_memory();
52 new->valid_hooks = u_repl->valid_hooks;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000053 strcpy(new->name, u_repl->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000054 new->nentries = u_repl->nentries;
55 new->num_counters = u_repl->num_counters;
56 new->counters = u_repl->counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +000057 // determine nr of udc
58 i = 0;
59 cl = u_repl->udc;
60 while (cl) {
61 i++;
62 cl = cl->next;
63 }
64 i += NF_BR_NUMHOOKS;
65 chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000066 // determine size
Bart De Schuymer60332e02002-06-23 08:01:47 +000067 i = 0;
68 cl = u_repl->udc;
69 while (1) {
70 if (i < NF_BR_NUMHOOKS) {
71 if (!(new->valid_hooks & (1 << i))) {
72 i++;
73 continue;
74 }
75 entries = u_repl->hook_entry[i];
76 } else {
77 if (!cl)
78 break;
79 entries = cl->udc;
80 }
81 chain_offsets[i] = entries_size;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000082 entries_size += sizeof(struct ebt_entries);
83 j = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +000084 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000085 while (e) {
86 j++;
87 entries_size += sizeof(struct ebt_entry);
88 m_l = e->m_list;
89 while (m_l) {
90 entries_size += m_l->m->match_size +
91 sizeof(struct ebt_entry_match);
92 m_l = m_l->next;
93 }
94 w_l = e->w_list;
95 while (w_l) {
96 entries_size += w_l->w->watcher_size +
97 sizeof(struct ebt_entry_watcher);
98 w_l = w_l->next;
99 }
100 entries_size += e->t->target_size +
101 sizeof(struct ebt_entry_target);
102 e = e->next;
103 }
104 // a little sanity check
Bart De Schuymer60332e02002-06-23 08:01:47 +0000105 if (j != entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000106 print_bug("Wrong nentries: %d != %d, hook = %s", j,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000107 entries->nentries, entries->name);
108 if (i >= NF_BR_NUMHOOKS)
109 cl = cl->next;
110 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000111 }
112
113 new->entries_size = entries_size;
114 new->entries = (char *)malloc(entries_size);
115 if (!new->entries)
116 print_memory();
117
118 // put everything in one block
119 p = new->entries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000120 i = 0;
121 cl = u_repl->udc;
122 while (1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000123 struct ebt_entries *hlp;
124
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000125 hlp = (struct ebt_entries *)p;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000126 if (i < NF_BR_NUMHOOKS) {
127 if (!(new->valid_hooks & (1 << i))) {
128 i++;
129 continue;
130 }
131 entries = u_repl->hook_entry[i];
132 new->hook_entry[i] = hlp;
133 } else {
134 if (!cl)
135 break;
136 entries = cl->udc;
137 }
138 hlp->nentries = entries->nentries;
139 hlp->policy = entries->policy;
140 strcpy(hlp->name, entries->name);
141 hlp->counter_offset = entries->counter_offset;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000142 hlp->distinguisher = 0; // make the kernel see the light
143 p += sizeof(struct ebt_entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000144 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000145 while (e) {
146 struct ebt_entry *tmp = (struct ebt_entry *)p;
147
148 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
149 tmp->invflags = e->invflags;
150 tmp->ethproto = e->ethproto;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000151 strcpy(tmp->in, e->in);
152 strcpy(tmp->out, e->out);
153 strcpy(tmp->logical_in, e->logical_in);
154 strcpy(tmp->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000155 memcpy(tmp->sourcemac, e->sourcemac,
156 sizeof(tmp->sourcemac));
157 memcpy(tmp->sourcemsk, e->sourcemsk,
158 sizeof(tmp->sourcemsk));
159 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
160 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
161
162 base = p;
163 p += sizeof(struct ebt_entry);
164 m_l = e->m_list;
165 while (m_l) {
166 memcpy(p, m_l->m, m_l->m->match_size +
167 sizeof(struct ebt_entry_match));
168 p += m_l->m->match_size +
169 sizeof(struct ebt_entry_match);
170 m_l = m_l->next;
171 }
172 tmp->watchers_offset = p - base;
173 w_l = e->w_list;
174 while (w_l) {
175 memcpy(p, w_l->w, w_l->w->watcher_size +
176 sizeof(struct ebt_entry_watcher));
177 p += w_l->w->watcher_size +
178 sizeof(struct ebt_entry_watcher);
179 w_l = w_l->next;
180 }
181 tmp->target_offset = p - base;
182 memcpy(p, e->t, e->t->target_size +
183 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000184 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
185 struct ebt_standard_target *st =
186 (struct ebt_standard_target *)p;
187 // translate the jump to a udc
188 if (st->verdict >= 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000189 st->verdict = chain_offsets
190 [st->verdict + NF_BR_NUMHOOKS];
Bart De Schuymer60332e02002-06-23 08:01:47 +0000191 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000192 p += e->t->target_size +
193 sizeof(struct ebt_entry_target);
194 tmp->next_offset = p - base;
195 e = e->next;
196 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000197 if (i >= NF_BR_NUMHOOKS)
198 cl = cl->next;
199 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000200 }
201
202 // sanity check
203 if (p - new->entries != new->entries_size)
204 print_bug("Entries_size bug");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000205 free(chain_offsets);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000206 return new;
207}
208
Bart De Schuymer62423742002-07-14 19:06:20 +0000209static void store_table_in_file(char *filename, struct ebt_replace *repl)
210{
211 char *command, *data;
212 int size;
213 FILE *file;
214
215 // start from an empty file with right priviliges
216 command = (char *)malloc(strlen(filename) + 15);
217 if (!command)
218 print_memory();
219 strcpy(command, "cat /dev/null>");
220 strcpy(command + 14, filename);
221 if (system(command))
222 print_error("Couldn't create file %s", filename);
223 strcpy(command, "chmod 600 ");
224 strcpy(command + 10, filename);
225 if (system(command))
226 print_error("Couldn't chmod file %s", filename);
227 free(command);
228
229 size = sizeof(struct ebt_replace) + repl->entries_size +
230 repl->nentries * sizeof(struct ebt_counter);
231 data = (char *)malloc(size);
232 if (!data)
233 print_memory();
234 memcpy(data, repl, sizeof(struct ebt_replace));
235 memcpy(data + sizeof(struct ebt_replace), repl->entries,
236 repl->entries_size);
237 // initialize counters to zero, deliver_counters() can update them
238 memset(data + sizeof(struct ebt_replace) + repl->entries_size,
239 0, repl->nentries * sizeof(struct ebt_counter));
240 if (!(file = fopen(filename, "wb")))
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000241 print_error("Couldn't open file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000242 if (fwrite(data, sizeof(char), size, file) != size) {
243 fclose(file);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000244 print_error("Couldn't write everything to file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000245 }
246 fclose(file);
247 free(data);
248}
249
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000250void deliver_table(struct ebt_u_replace *u_repl)
251{
252 socklen_t optlen;
253 struct ebt_replace *repl;
254
255 // translate the struct ebt_u_replace to a struct ebt_replace
256 repl = translate_user2kernel(u_repl);
Bart De Schuymer62423742002-07-14 19:06:20 +0000257 if (u_repl->filename != NULL) {
258 store_table_in_file(u_repl->filename, repl);
259 return;
260 }
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000261 // give the data to the kernel
262 optlen = sizeof(struct ebt_replace) + repl->entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000263 get_sockfd();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000264 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
Bart De Schuymer73564dc2002-06-05 18:13:51 +0000265 print_error("The kernel doesn't support a certain ebtables"
266 " extension, consider recompiling your kernel or insmod"
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000267 " the extension");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000268}
269
Bart De Schuymer62423742002-07-14 19:06:20 +0000270static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
271{
272 int size = repl->nentries * sizeof(struct ebt_counter);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000273 unsigned int entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000274 struct ebt_replace hlp;
275 FILE *file;
276
277 if (!(file = fopen(filename, "r+b")))
278 print_error("Could not open file %s", filename);
279 // find out entries_size and then set the file pointer to the counters
280 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
281 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
282 sizeof(unsigned int) ||
283 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
284 fclose(file);
285 print_error("File %s is corrupt", filename);
286 }
287 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
288 fclose(file);
289 print_error("Could not write everything to file %s", filename);
290 }
291 fclose(file);
292}
293
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000294// gets executed after deliver_table
295void
Bart De Schuymered053432002-07-21 19:35:39 +0000296deliver_counters(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000297{
298 unsigned short *point;
299 struct ebt_counter *old, *new, *newcounters;
300 socklen_t optlen;
301 struct ebt_replace repl;
Bart De Schuymered053432002-07-21 19:35:39 +0000302 unsigned short *counterchanges = u_repl->counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000303
304 if (u_repl->nentries == 0)
305 return;
306
307 newcounters = (struct ebt_counter *)
308 malloc(u_repl->nentries * sizeof(struct ebt_counter));
309 if (!newcounters)
310 print_memory();
311 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
312 old = u_repl->counters;
313 new = newcounters;
314 point = counterchanges;
315 while (*point != CNT_END) {
316 if (*point == CNT_NORM) {
317 // 'normal' rule, meaning we didn't do anything to it
318 // So, we just copy
319 new->pcnt = old->pcnt;
320 // we've used an old counter
321 old++;
322 // we've set a new counter
323 new++;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000324 } else if (*point == CNT_DEL) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000325 // don't use this old counter
326 old++;
327 } else if (*point == CNT_ADD) {
328 // new counter, let it stay 0
329 new++;
330 } else {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000331 // zero it (let it stay 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000332 old++;
333 new++;
334 }
335 point++;
336 }
337
338 free(u_repl->counters);
339 u_repl->counters = newcounters;
340 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000341 if (u_repl->filename != NULL) {
342 store_counters_in_file(u_repl->filename, u_repl);
343 return;
344 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000345 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
346 sizeof(struct ebt_replace);
347 // now put the stuff in the kernel's struct ebt_replace
348 repl.counters = u_repl->counters;
349 repl.num_counters = u_repl->num_counters;
350 memcpy(repl.name, u_repl->name, sizeof(repl.name));
351
352 get_sockfd();
353 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000354 print_bug("Couldn't update kernel counters");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000355}
356
357static int
358ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
359{
360 struct ebt_u_match_list *new;
361
362 new = (struct ebt_u_match_list *)
363 malloc(sizeof(struct ebt_u_match_list));
364 if (!new)
365 print_memory();
366 new->m = (struct ebt_entry_match *)
367 malloc(m->match_size + sizeof(struct ebt_entry_match));
368 if (!new->m)
369 print_memory();
370 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
371 new->next = NULL;
372 **l = new;
373 *l = &new->next;
374 if (find_match(new->m->u.name) == NULL)
375 print_error("Kernel match %s unsupported by userspace tool",
376 new->m->u.name);
377 return 0;
378}
379
380static int
381ebt_translate_watcher(struct ebt_entry_watcher *w,
382 struct ebt_u_watcher_list ***l)
383{
384 struct ebt_u_watcher_list *new;
385
386 new = (struct ebt_u_watcher_list *)
387 malloc(sizeof(struct ebt_u_watcher_list));
388 if (!new)
389 print_memory();
390 new->w = (struct ebt_entry_watcher *)
391 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
392 if (!new->w)
393 print_memory();
394 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
395 new->next = NULL;
396 **l = new;
397 *l = &new->next;
398 if (find_watcher(new->w->u.name) == NULL)
399 print_error("Kernel watcher %s unsupported by userspace tool",
400 new->w->u.name);
401 return 0;
402}
403
404static int
405ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
406 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000407 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000408{
409 // an entry
410 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
411 struct ebt_u_entry *new;
412 struct ebt_u_match_list **m_l;
413 struct ebt_u_watcher_list **w_l;
414 struct ebt_entry_target *t;
415
416 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
417 if (!new)
418 print_memory();
419 new->bitmask = e->bitmask;
420 // plain userspace code doesn't know about EBT_ENTRY_OR_ENTRIES
421 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
422 new->invflags = e->invflags;
423 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000424 strcpy(new->in, e->in);
425 strcpy(new->out, e->out);
426 strcpy(new->logical_in, e->logical_in);
427 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000428 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
429 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
430 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
431 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
432 new->m_list = NULL;
433 new->w_list = NULL;
434 new->next = NULL;
435 m_l = &new->m_list;
436 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
437 w_l = &new->w_list;
438 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
439
440 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
441 new->t = (struct ebt_entry_target *)
442 malloc(t->target_size + sizeof(struct ebt_entry_target));
443 if (!new->t)
444 print_memory();
445 if (find_target(t->u.name) == NULL)
446 print_error("Kernel target %s unsupported by "
447 "userspace tool", t->u.name);
448 memcpy(new->t, t, t->target_size +
449 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000450 // deal with jumps to udc
451 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
452 char *tmp = base;
453 int verdict = ((struct ebt_standard_target *)t)->verdict;
454 int i;
455 struct ebt_u_chain_list *cl;
456
457 if (verdict >= 0) {
458 tmp += verdict;
459 cl = u_repl->udc;
460 i = 0;
461 while (cl && cl->kernel_start != tmp) {
462 i++;
463 cl = cl->next;
464 }
465 if (!cl)
466 print_bug("can't find udc for jump");
467 ((struct ebt_standard_target *)new->t)->verdict = i;
468 }
469 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000470
471 // I love pointers
472 **u_e = new;
473 *u_e = &new->next;
474 (*cnt)++;
475 (*totalcnt)++;
476 return 0;
477 } else { // a new chain
478 int i;
479 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000480 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000481
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000482 if (*n != *cnt)
483 print_bug("Nr of entries in the chain is wrong");
484 *n = entries->nentries;
485 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000486 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
487 if (valid_hooks & (1 << i))
488 break;
489 *hook = i;
490 // makes use of fact that standard chains come before udc
491 if (i >= NF_BR_NUMHOOKS) { // udc
492 i -= NF_BR_NUMHOOKS;
493 cl = u_repl->udc;
494 while (i-- > 0)
495 cl = cl->next;
496 *u_e = &(cl->udc->entries);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000497 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000498 *u_e = &(u_repl->hook_entry[*hook]->entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000499 return 0;
500 }
501}
502
503// initialize all chain headers
504static int
505ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
506 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
507{
508 int i;
509 struct ebt_entries *entries = (struct ebt_entries *)e;
510 struct ebt_u_entries *new;
511 struct ebt_u_chain_list **chain_list;
512
513 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
514 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
515 if (valid_hooks & (1 << i))
516 break;
517 // makes use of fact that standard chains come before udc
518 if (i >= NF_BR_NUMHOOKS) { // udc
519 chain_list = &u_repl->udc;
520 // add in the back
521 while (*chain_list)
522 chain_list = &((*chain_list)->next);
523 *chain_list = (struct ebt_u_chain_list *)
524 malloc(sizeof(struct ebt_u_chain_list));
525 if (!(*chain_list))
526 print_memory();
527 (*chain_list)->next = NULL;
528 (*chain_list)->udc = (struct ebt_u_entries *)
529 malloc(sizeof(struct ebt_u_entries));
530 if (!((*chain_list)->udc))
531 print_memory();
532 new = (*chain_list)->udc;
533 // ebt_translate_entry depends on this for knowing
534 // to which chain is being jumped
535 (*chain_list)->kernel_start = (char *)e;
536 } else {
537 *hook = i;
538 new = (struct ebt_u_entries *)
539 malloc(sizeof(struct ebt_u_entries));
540 if (!new)
541 print_memory();
542 u_repl->hook_entry[*hook] = new;
543 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000544 new->nentries = entries->nentries;
545 new->policy = entries->policy;
546 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000547 new->counter_offset = entries->counter_offset;
548 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000549 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000550 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000551}
552
Bart De Schuymer62423742002-07-14 19:06:20 +0000553static void retrieve_from_file(char *filename, struct ebt_replace *repl,
554 char command)
555{
556 FILE *file;
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000557 char *hlp = NULL;
Bart De Schuymer62423742002-07-14 19:06:20 +0000558 int size;
559
560 if (!(file = fopen(filename, "r+b")))
561 print_error("Could not open file %s", filename);
562 // make sure table name is right if command isn't -L or --atomic-commit
563 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000564 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000565 if (!hlp)
566 print_memory();
567 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000568 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000569 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
570 != sizeof(struct ebt_replace))
571 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000572 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
573 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000574 print_error("File %s contains wrong table name or is corrupt",
575 filename);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000576 free(hlp);
577 } else if (!find_table(repl->name)) {
578 fclose(file);
579 print_error("File %s contains invalid table name", filename);
580 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000581
Bart De Schuymer62423742002-07-14 19:06:20 +0000582 size = sizeof(struct ebt_replace) +
583 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
584 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000585 if (size != ftell(file)) {
586 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000587 print_error("File %s has wrong size", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000588 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000589 repl->entries = (char *)malloc(repl->entries_size);
590 if (!repl->entries)
591 print_memory();
592 if (repl->nentries) {
593 repl->counters = (struct ebt_counter *)
594 malloc(repl->nentries * sizeof(struct ebt_counter));
595 if (!repl->counters)
596 print_memory();
597 } else
598 repl->counters = NULL;
599 // copy entries and counters
600 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
601 fread(repl->entries, sizeof(char), repl->entries_size, file)
602 != repl->entries_size ||
603 fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
604 || fread(repl->counters, sizeof(char),
605 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000606 != repl->nentries * sizeof(struct ebt_counter)) {
607 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000608 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000609 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000610 fclose(file);
611}
612
613static int retrieve_from_kernel(struct ebt_replace *repl, char command)
614{
615 socklen_t optlen;
616 int optname;
617
618 optlen = sizeof(struct ebt_replace);
619 get_sockfd();
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000620 // --atomic-init || --init-table
621 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000622 optname = EBT_SO_GET_INIT_INFO;
623 else
624 optname = EBT_SO_GET_INFO;
625 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
626 return -1;
627
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000628 if ( !(repl->entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer62423742002-07-14 19:06:20 +0000629 print_memory();
630 if (repl->nentries) {
631 if (!(repl->counters = (struct ebt_counter *)
632 malloc(repl->nentries * sizeof(struct ebt_counter))) )
633 print_memory();
634 }
635 else
636 repl->counters = NULL;
637
638 // we want to receive the counters
639 repl->num_counters = repl->nentries;
640 optlen += repl->entries_size + repl->num_counters *
641 sizeof(struct ebt_counter);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000642 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000643 optname = EBT_SO_GET_INIT_ENTRIES;
644 else
645 optname = EBT_SO_GET_ENTRIES;
646 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
647 print_bug("hmm, what is wrong??? bug#1");
648
649 return 0;
650}
651
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000652int get_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000653{
654 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000655 struct ebt_replace repl;
656 struct ebt_u_entry **u_e;
657
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000658 strcpy(repl.name, u_repl->name);
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000659 if (u_repl->filename != NULL) {
Bart De Schuymer62423742002-07-14 19:06:20 +0000660 retrieve_from_file(u_repl->filename, &repl, u_repl->command);
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000661 // -L with a wrong table name should be dealt with silently
662 strcpy(u_repl->name, repl.name);
663 } else if (retrieve_from_kernel(&repl, u_repl->command) == -1)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000664 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}