blob: 82888c03f462d01ea4c5e6d89d072343d7cf2227 [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
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00008/*
9 * All the userspace/kernel communication is in this file.
10 * The other code should not have to know anything about the way the
11 * kernel likes the structure of the table data.
12 * The other code works with linked lists, lots of linked lists.
13 * So, the translation is done here.
14 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000015
16#include <getopt.h>
17#include <string.h>
18#include <errno.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <sys/socket.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000022#include "include/ebtables_u.h"
23
24extern char* hooknames[NF_BR_NUMHOOKS];
25
26int sockfd = -1;
27
Bart De Schuymer62423742002-07-14 19:06:20 +000028static void get_sockfd()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000029{
30 if (sockfd == -1) {
31 sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
32 if (sockfd < 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000033 print_error("Problem getting a socket, "
Bart De Schuymer06b4fd22002-08-01 15:08:28 +000034 "you probably don't have the right "
35 "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 Schuymer9895a8e2003-01-11 10:14:24 +000059 /* determine nr of udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +000060 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 Schuymer9895a8e2003-01-11 10:14:24 +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 }
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000106 /* 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
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000120 /* put everything in one block */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000121 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 Schuymer9895a8e2003-01-11 10:14:24 +0000144 hlp->distinguisher = 0; /* make the kernel see the light */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000145 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;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000189 /* translate the jump to a udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000190 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
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000204 /* sanity check */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000205 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
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000217 /* start from an empty file with right priviliges */
Bart De Schuymer62423742002-07-14 19:06:20 +0000218 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);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000239 /* initialize counters to zero, deliver_counters() can update them */
Bart De Schuymer62423742002-07-14 19:06:20 +0000240 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
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000257 /* translate the struct ebt_u_replace to a struct ebt_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000258 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 Schuymer9895a8e2003-01-11 10:14:24 +0000263 /* give the data to the kernel */
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000264 optlen = sizeof(struct ebt_replace) + repl->entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000265 get_sockfd();
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000266 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
267 return;
268 if (u_repl->command == 8) { /* the ebtables module may not
269 * yet be loaded with --atomic-commit */
270 ebtables_insmod("ebtables");
271 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES,
272 repl, optlen))
273 return;
274 }
275
276 print_error("The kernel doesn't support a certain ebtables"
277 " extension, consider recompiling your kernel or insmod"
278 " the extension");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000279}
280
Bart De Schuymer62423742002-07-14 19:06:20 +0000281static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
282{
283 int size = repl->nentries * sizeof(struct ebt_counter);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000284 unsigned int entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000285 struct ebt_replace hlp;
286 FILE *file;
287
288 if (!(file = fopen(filename, "r+b")))
289 print_error("Could not open file %s", filename);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000290 /*
291 * find out entries_size and then set the file pointer to the
292 * counters
293 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000294 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
295 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
296 sizeof(unsigned int) ||
297 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
298 fclose(file);
299 print_error("File %s is corrupt", filename);
300 }
301 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
302 fclose(file);
303 print_error("Could not write everything to file %s", filename);
304 }
305 fclose(file);
306}
307
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000308/* gets executed after deliver_table */
309void deliver_counters(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000310{
311 unsigned short *point;
312 struct ebt_counter *old, *new, *newcounters;
313 socklen_t optlen;
314 struct ebt_replace repl;
Bart De Schuymered053432002-07-21 19:35:39 +0000315 unsigned short *counterchanges = u_repl->counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000316
317 if (u_repl->nentries == 0)
318 return;
319
320 newcounters = (struct ebt_counter *)
321 malloc(u_repl->nentries * sizeof(struct ebt_counter));
322 if (!newcounters)
323 print_memory();
324 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
325 old = u_repl->counters;
326 new = newcounters;
327 point = counterchanges;
328 while (*point != CNT_END) {
329 if (*point == CNT_NORM) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000330 /*
331 *'normal' rule, meaning we didn't do anything to it
332 * So, we just copy
333 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000334 new->pcnt = old->pcnt;
Bart De Schuymer6d06d262003-05-01 19:38:54 +0000335 new->bcnt = old->bcnt;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000336 /* we've used an old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000337 old++;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000338 /* we've set a new counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000339 new++;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000340 } else if (*point == CNT_DEL) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000341 /* don't use this old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000342 old++;
343 } else if (*point == CNT_ADD) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000344 /* new counter, let it stay 0 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000345 new++;
346 } else {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000347 /* zero it (let it stay 0) */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000348 old++;
349 new++;
350 }
351 point++;
352 }
353
354 free(u_repl->counters);
355 u_repl->counters = newcounters;
356 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000357 if (u_repl->filename != NULL) {
358 store_counters_in_file(u_repl->filename, u_repl);
359 return;
360 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000361 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
362 sizeof(struct ebt_replace);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000363 /* now put the stuff in the kernel's struct ebt_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000364 repl.counters = u_repl->counters;
365 repl.num_counters = u_repl->num_counters;
366 memcpy(repl.name, u_repl->name, sizeof(repl.name));
367
368 get_sockfd();
369 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000370 print_bug("Couldn't update kernel counters");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000371}
372
373static int
374ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
375{
376 struct ebt_u_match_list *new;
377
378 new = (struct ebt_u_match_list *)
379 malloc(sizeof(struct ebt_u_match_list));
380 if (!new)
381 print_memory();
382 new->m = (struct ebt_entry_match *)
383 malloc(m->match_size + sizeof(struct ebt_entry_match));
384 if (!new->m)
385 print_memory();
386 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
387 new->next = NULL;
388 **l = new;
389 *l = &new->next;
390 if (find_match(new->m->u.name) == NULL)
391 print_error("Kernel match %s unsupported by userspace tool",
392 new->m->u.name);
393 return 0;
394}
395
396static int
397ebt_translate_watcher(struct ebt_entry_watcher *w,
398 struct ebt_u_watcher_list ***l)
399{
400 struct ebt_u_watcher_list *new;
401
402 new = (struct ebt_u_watcher_list *)
403 malloc(sizeof(struct ebt_u_watcher_list));
404 if (!new)
405 print_memory();
406 new->w = (struct ebt_entry_watcher *)
407 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
408 if (!new->w)
409 print_memory();
410 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
411 new->next = NULL;
412 **l = new;
413 *l = &new->next;
414 if (find_watcher(new->w->u.name) == NULL)
415 print_error("Kernel watcher %s unsupported by userspace tool",
416 new->w->u.name);
417 return 0;
418}
419
420static int
421ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
422 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000423 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000424{
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000425 /* an entry */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000426 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
427 struct ebt_u_entry *new;
428 struct ebt_u_match_list **m_l;
429 struct ebt_u_watcher_list **w_l;
430 struct ebt_entry_target *t;
431
432 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
433 if (!new)
434 print_memory();
435 new->bitmask = e->bitmask;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000436 /*
437 * plain userspace code doesn't know about
438 * EBT_ENTRY_OR_ENTRIES
439 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000440 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
441 new->invflags = e->invflags;
442 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000443 strcpy(new->in, e->in);
444 strcpy(new->out, e->out);
445 strcpy(new->logical_in, e->logical_in);
446 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000447 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
448 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
449 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
450 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
451 new->m_list = NULL;
452 new->w_list = NULL;
453 new->next = NULL;
454 m_l = &new->m_list;
455 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
456 w_l = &new->w_list;
457 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
458
459 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
460 new->t = (struct ebt_entry_target *)
461 malloc(t->target_size + sizeof(struct ebt_entry_target));
462 if (!new->t)
463 print_memory();
464 if (find_target(t->u.name) == NULL)
465 print_error("Kernel target %s unsupported by "
466 "userspace tool", t->u.name);
467 memcpy(new->t, t, t->target_size +
468 sizeof(struct ebt_entry_target));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000469 /* deal with jumps to udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000470 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
471 char *tmp = base;
472 int verdict = ((struct ebt_standard_target *)t)->verdict;
473 int i;
474 struct ebt_u_chain_list *cl;
475
476 if (verdict >= 0) {
477 tmp += verdict;
478 cl = u_repl->udc;
479 i = 0;
480 while (cl && cl->kernel_start != tmp) {
481 i++;
482 cl = cl->next;
483 }
484 if (!cl)
485 print_bug("can't find udc for jump");
486 ((struct ebt_standard_target *)new->t)->verdict = i;
487 }
488 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000489
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000490 /* I love pointers */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000491 **u_e = new;
492 *u_e = &new->next;
493 (*cnt)++;
494 (*totalcnt)++;
495 return 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000496 } else { /* a new chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000497 int i;
498 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000499 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000500
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000501 if (*n != *cnt)
502 print_bug("Nr of entries in the chain is wrong");
503 *n = entries->nentries;
504 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000505 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
506 if (valid_hooks & (1 << i))
507 break;
508 *hook = i;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000509 /* makes use of fact that standard chains come before udc */
510 if (i >= NF_BR_NUMHOOKS) { /* udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000511 i -= NF_BR_NUMHOOKS;
512 cl = u_repl->udc;
513 while (i-- > 0)
514 cl = cl->next;
515 *u_e = &(cl->udc->entries);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000516 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000517 *u_e = &(u_repl->hook_entry[*hook]->entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000518 return 0;
519 }
520}
521
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000522/* initialize all chain headers */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000523static int
524ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
525 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
526{
527 int i;
528 struct ebt_entries *entries = (struct ebt_entries *)e;
529 struct ebt_u_entries *new;
530 struct ebt_u_chain_list **chain_list;
531
532 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
533 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
534 if (valid_hooks & (1 << i))
535 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000536 /* makes use of fact that standard chains come before udc */
537 if (i >= NF_BR_NUMHOOKS) { /* udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000538 chain_list = &u_repl->udc;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000539 /* add in the back */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000540 while (*chain_list)
541 chain_list = &((*chain_list)->next);
542 *chain_list = (struct ebt_u_chain_list *)
543 malloc(sizeof(struct ebt_u_chain_list));
544 if (!(*chain_list))
545 print_memory();
546 (*chain_list)->next = NULL;
547 (*chain_list)->udc = (struct ebt_u_entries *)
548 malloc(sizeof(struct ebt_u_entries));
549 if (!((*chain_list)->udc))
550 print_memory();
551 new = (*chain_list)->udc;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000552 /*
553 * ebt_translate_entry depends on this for knowing
554 * to which chain is being jumped
555 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000556 (*chain_list)->kernel_start = (char *)e;
557 } else {
558 *hook = i;
559 new = (struct ebt_u_entries *)
560 malloc(sizeof(struct ebt_u_entries));
561 if (!new)
562 print_memory();
563 u_repl->hook_entry[*hook] = new;
564 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000565 new->nentries = entries->nentries;
566 new->policy = entries->policy;
567 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000568 new->counter_offset = entries->counter_offset;
569 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000570 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000571 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000572}
573
Bart De Schuymer62423742002-07-14 19:06:20 +0000574static void retrieve_from_file(char *filename, struct ebt_replace *repl,
575 char command)
576{
577 FILE *file;
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000578 char *hlp = NULL;
Bart De Schuymer62423742002-07-14 19:06:20 +0000579 int size;
580
581 if (!(file = fopen(filename, "r+b")))
582 print_error("Could not open file %s", filename);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000583 /*
584 * make sure table name is right if command isn't -L or --atomic-commit
585 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000586 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000587 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000588 if (!hlp)
589 print_memory();
590 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000591 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000592 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
593 != sizeof(struct ebt_replace))
594 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000595 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
596 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000597 print_error("File %s contains wrong table name or is corrupt",
598 filename);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000599 free(hlp);
600 } else if (!find_table(repl->name)) {
601 fclose(file);
602 print_error("File %s contains invalid table name", filename);
603 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000604
Bart De Schuymer62423742002-07-14 19:06:20 +0000605 size = sizeof(struct ebt_replace) +
606 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
607 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000608 if (size != ftell(file)) {
609 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000610 print_error("File %s has wrong size", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000611 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000612 repl->entries = (char *)malloc(repl->entries_size);
613 if (!repl->entries)
614 print_memory();
615 if (repl->nentries) {
616 repl->counters = (struct ebt_counter *)
617 malloc(repl->nentries * sizeof(struct ebt_counter));
618 if (!repl->counters)
619 print_memory();
620 } else
621 repl->counters = NULL;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000622 /* copy entries and counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000623 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
624 fread(repl->entries, sizeof(char), repl->entries_size, file)
625 != repl->entries_size ||
626 fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
627 || fread(repl->counters, sizeof(char),
628 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000629 != repl->nentries * sizeof(struct ebt_counter)) {
630 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000631 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000632 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000633 fclose(file);
634}
635
636static int retrieve_from_kernel(struct ebt_replace *repl, char command)
637{
638 socklen_t optlen;
639 int optname;
640
641 optlen = sizeof(struct ebt_replace);
642 get_sockfd();
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000643 /* --atomic-init || --init-table */
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_INFO;
646 else
647 optname = EBT_SO_GET_INFO;
648 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
649 return -1;
650
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000651 if ( !(repl->entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer62423742002-07-14 19:06:20 +0000652 print_memory();
653 if (repl->nentries) {
654 if (!(repl->counters = (struct ebt_counter *)
655 malloc(repl->nentries * sizeof(struct ebt_counter))) )
656 print_memory();
657 }
658 else
659 repl->counters = NULL;
660
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000661 /* we want to receive the counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000662 repl->num_counters = repl->nentries;
663 optlen += repl->entries_size + repl->num_counters *
664 sizeof(struct ebt_counter);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000665 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000666 optname = EBT_SO_GET_INIT_ENTRIES;
667 else
668 optname = EBT_SO_GET_ENTRIES;
669 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
670 print_bug("hmm, what is wrong??? bug#1");
671
672 return 0;
673}
674
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000675int get_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000676{
677 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000678 struct ebt_replace repl;
679 struct ebt_u_entry **u_e;
680
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000681 strcpy(repl.name, u_repl->name);
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000682 if (u_repl->filename != NULL) {
Bart De Schuymer62423742002-07-14 19:06:20 +0000683 retrieve_from_file(u_repl->filename, &repl, u_repl->command);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000684 /*
685 * -L with a wrong table name should be dealt with silently
686 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000687 strcpy(u_repl->name, repl.name);
688 } else if (retrieve_from_kernel(&repl, u_repl->command) == -1)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000689 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000690
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000691 /* translate the struct ebt_replace to a struct ebt_u_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000692 u_repl->valid_hooks = repl.valid_hooks;
693 u_repl->nentries = repl.nentries;
694 u_repl->num_counters = repl.num_counters;
695 u_repl->counters = repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000696 u_repl->udc = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000697 hook = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000698 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
699 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000700 i = 0; /* holds the expected nr. of entries for the chain */
701 j = 0; /* holds the up to now counted entries for the chain */
702 /*
703 * holds the total nr. of entries,
704 * should equal u_repl->nentries afterwards
705 */
706 k = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000707 hook = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000708 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000709 &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks, repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000710 if (k != u_repl->nentries)
711 print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000712 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000713}