blob: ab2132754dda5675ff0109b2229cbbd1b34a7570 [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 Schuymer1abc55d2002-06-01 19:23:47 +0000266 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
Bart De Schuymer73564dc2002-06-05 18:13:51 +0000267 print_error("The kernel doesn't support a certain ebtables"
268 " extension, consider recompiling your kernel or insmod"
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000269 " the extension");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000270}
271
Bart De Schuymer62423742002-07-14 19:06:20 +0000272static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
273{
274 int size = repl->nentries * sizeof(struct ebt_counter);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000275 unsigned int entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000276 struct ebt_replace hlp;
277 FILE *file;
278
279 if (!(file = fopen(filename, "r+b")))
280 print_error("Could not open file %s", filename);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000281 /*
282 * find out entries_size and then set the file pointer to the
283 * counters
284 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000285 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
286 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
287 sizeof(unsigned int) ||
288 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
289 fclose(file);
290 print_error("File %s is corrupt", filename);
291 }
292 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
293 fclose(file);
294 print_error("Could not write everything to file %s", filename);
295 }
296 fclose(file);
297}
298
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000299/* gets executed after deliver_table */
300void deliver_counters(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000301{
302 unsigned short *point;
303 struct ebt_counter *old, *new, *newcounters;
304 socklen_t optlen;
305 struct ebt_replace repl;
Bart De Schuymered053432002-07-21 19:35:39 +0000306 unsigned short *counterchanges = u_repl->counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000307
308 if (u_repl->nentries == 0)
309 return;
310
311 newcounters = (struct ebt_counter *)
312 malloc(u_repl->nentries * sizeof(struct ebt_counter));
313 if (!newcounters)
314 print_memory();
315 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
316 old = u_repl->counters;
317 new = newcounters;
318 point = counterchanges;
319 while (*point != CNT_END) {
320 if (*point == CNT_NORM) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000321 /*
322 *'normal' rule, meaning we didn't do anything to it
323 * So, we just copy
324 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000325 new->pcnt = old->pcnt;
Bart De Schuymer6d06d262003-05-01 19:38:54 +0000326 new->bcnt = old->bcnt;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000327 /* we've used an old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000328 old++;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000329 /* we've set a new counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000330 new++;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000331 } else if (*point == CNT_DEL) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000332 /* don't use this old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000333 old++;
334 } else if (*point == CNT_ADD) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000335 /* new counter, let it stay 0 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000336 new++;
337 } else {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000338 /* zero it (let it stay 0) */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000339 old++;
340 new++;
341 }
342 point++;
343 }
344
345 free(u_repl->counters);
346 u_repl->counters = newcounters;
347 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000348 if (u_repl->filename != NULL) {
349 store_counters_in_file(u_repl->filename, u_repl);
350 return;
351 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000352 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
353 sizeof(struct ebt_replace);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000354 /* now put the stuff in the kernel's struct ebt_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000355 repl.counters = u_repl->counters;
356 repl.num_counters = u_repl->num_counters;
357 memcpy(repl.name, u_repl->name, sizeof(repl.name));
358
359 get_sockfd();
360 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000361 print_bug("Couldn't update kernel counters");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000362}
363
364static int
365ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
366{
367 struct ebt_u_match_list *new;
368
369 new = (struct ebt_u_match_list *)
370 malloc(sizeof(struct ebt_u_match_list));
371 if (!new)
372 print_memory();
373 new->m = (struct ebt_entry_match *)
374 malloc(m->match_size + sizeof(struct ebt_entry_match));
375 if (!new->m)
376 print_memory();
377 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
378 new->next = NULL;
379 **l = new;
380 *l = &new->next;
381 if (find_match(new->m->u.name) == NULL)
382 print_error("Kernel match %s unsupported by userspace tool",
383 new->m->u.name);
384 return 0;
385}
386
387static int
388ebt_translate_watcher(struct ebt_entry_watcher *w,
389 struct ebt_u_watcher_list ***l)
390{
391 struct ebt_u_watcher_list *new;
392
393 new = (struct ebt_u_watcher_list *)
394 malloc(sizeof(struct ebt_u_watcher_list));
395 if (!new)
396 print_memory();
397 new->w = (struct ebt_entry_watcher *)
398 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
399 if (!new->w)
400 print_memory();
401 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
402 new->next = NULL;
403 **l = new;
404 *l = &new->next;
405 if (find_watcher(new->w->u.name) == NULL)
406 print_error("Kernel watcher %s unsupported by userspace tool",
407 new->w->u.name);
408 return 0;
409}
410
411static int
412ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
413 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000414 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000415{
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000416 /* an entry */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000417 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
418 struct ebt_u_entry *new;
419 struct ebt_u_match_list **m_l;
420 struct ebt_u_watcher_list **w_l;
421 struct ebt_entry_target *t;
422
423 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
424 if (!new)
425 print_memory();
426 new->bitmask = e->bitmask;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000427 /*
428 * plain userspace code doesn't know about
429 * EBT_ENTRY_OR_ENTRIES
430 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000431 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
432 new->invflags = e->invflags;
433 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000434 strcpy(new->in, e->in);
435 strcpy(new->out, e->out);
436 strcpy(new->logical_in, e->logical_in);
437 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000438 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
439 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
440 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
441 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
442 new->m_list = NULL;
443 new->w_list = NULL;
444 new->next = NULL;
445 m_l = &new->m_list;
446 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
447 w_l = &new->w_list;
448 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
449
450 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
451 new->t = (struct ebt_entry_target *)
452 malloc(t->target_size + sizeof(struct ebt_entry_target));
453 if (!new->t)
454 print_memory();
455 if (find_target(t->u.name) == NULL)
456 print_error("Kernel target %s unsupported by "
457 "userspace tool", t->u.name);
458 memcpy(new->t, t, t->target_size +
459 sizeof(struct ebt_entry_target));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000460 /* deal with jumps to udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000461 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
462 char *tmp = base;
463 int verdict = ((struct ebt_standard_target *)t)->verdict;
464 int i;
465 struct ebt_u_chain_list *cl;
466
467 if (verdict >= 0) {
468 tmp += verdict;
469 cl = u_repl->udc;
470 i = 0;
471 while (cl && cl->kernel_start != tmp) {
472 i++;
473 cl = cl->next;
474 }
475 if (!cl)
476 print_bug("can't find udc for jump");
477 ((struct ebt_standard_target *)new->t)->verdict = i;
478 }
479 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000480
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000481 /* I love pointers */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000482 **u_e = new;
483 *u_e = &new->next;
484 (*cnt)++;
485 (*totalcnt)++;
486 return 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000487 } else { /* a new chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000488 int i;
489 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000490 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000491
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000492 if (*n != *cnt)
493 print_bug("Nr of entries in the chain is wrong");
494 *n = entries->nentries;
495 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000496 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
497 if (valid_hooks & (1 << i))
498 break;
499 *hook = i;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000500 /* makes use of fact that standard chains come before udc */
501 if (i >= NF_BR_NUMHOOKS) { /* udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000502 i -= NF_BR_NUMHOOKS;
503 cl = u_repl->udc;
504 while (i-- > 0)
505 cl = cl->next;
506 *u_e = &(cl->udc->entries);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000507 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000508 *u_e = &(u_repl->hook_entry[*hook]->entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000509 return 0;
510 }
511}
512
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000513/* initialize all chain headers */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000514static int
515ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
516 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
517{
518 int i;
519 struct ebt_entries *entries = (struct ebt_entries *)e;
520 struct ebt_u_entries *new;
521 struct ebt_u_chain_list **chain_list;
522
523 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
524 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
525 if (valid_hooks & (1 << i))
526 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000527 /* makes use of fact that standard chains come before udc */
528 if (i >= NF_BR_NUMHOOKS) { /* udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000529 chain_list = &u_repl->udc;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000530 /* add in the back */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000531 while (*chain_list)
532 chain_list = &((*chain_list)->next);
533 *chain_list = (struct ebt_u_chain_list *)
534 malloc(sizeof(struct ebt_u_chain_list));
535 if (!(*chain_list))
536 print_memory();
537 (*chain_list)->next = NULL;
538 (*chain_list)->udc = (struct ebt_u_entries *)
539 malloc(sizeof(struct ebt_u_entries));
540 if (!((*chain_list)->udc))
541 print_memory();
542 new = (*chain_list)->udc;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000543 /*
544 * ebt_translate_entry depends on this for knowing
545 * to which chain is being jumped
546 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000547 (*chain_list)->kernel_start = (char *)e;
548 } else {
549 *hook = i;
550 new = (struct ebt_u_entries *)
551 malloc(sizeof(struct ebt_u_entries));
552 if (!new)
553 print_memory();
554 u_repl->hook_entry[*hook] = new;
555 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000556 new->nentries = entries->nentries;
557 new->policy = entries->policy;
558 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000559 new->counter_offset = entries->counter_offset;
560 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000561 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000562 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000563}
564
Bart De Schuymer62423742002-07-14 19:06:20 +0000565static void retrieve_from_file(char *filename, struct ebt_replace *repl,
566 char command)
567{
568 FILE *file;
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000569 char *hlp = NULL;
Bart De Schuymer62423742002-07-14 19:06:20 +0000570 int size;
571
572 if (!(file = fopen(filename, "r+b")))
573 print_error("Could not open file %s", filename);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000574 /*
575 * make sure table name is right if command isn't -L or --atomic-commit
576 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000577 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000578 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000579 if (!hlp)
580 print_memory();
581 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000582 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000583 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
584 != sizeof(struct ebt_replace))
585 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000586 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
587 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000588 print_error("File %s contains wrong table name or is corrupt",
589 filename);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000590 free(hlp);
591 } else if (!find_table(repl->name)) {
592 fclose(file);
593 print_error("File %s contains invalid table name", filename);
594 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000595
Bart De Schuymer62423742002-07-14 19:06:20 +0000596 size = sizeof(struct ebt_replace) +
597 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
598 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000599 if (size != ftell(file)) {
600 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000601 print_error("File %s has wrong size", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000602 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000603 repl->entries = (char *)malloc(repl->entries_size);
604 if (!repl->entries)
605 print_memory();
606 if (repl->nentries) {
607 repl->counters = (struct ebt_counter *)
608 malloc(repl->nentries * sizeof(struct ebt_counter));
609 if (!repl->counters)
610 print_memory();
611 } else
612 repl->counters = NULL;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000613 /* copy entries and counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000614 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
615 fread(repl->entries, sizeof(char), repl->entries_size, file)
616 != repl->entries_size ||
617 fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
618 || fread(repl->counters, sizeof(char),
619 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000620 != repl->nentries * sizeof(struct ebt_counter)) {
621 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000622 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000623 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000624 fclose(file);
625}
626
627static int retrieve_from_kernel(struct ebt_replace *repl, char command)
628{
629 socklen_t optlen;
630 int optname;
631
632 optlen = sizeof(struct ebt_replace);
633 get_sockfd();
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000634 /* --atomic-init || --init-table */
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000635 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000636 optname = EBT_SO_GET_INIT_INFO;
637 else
638 optname = EBT_SO_GET_INFO;
639 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
640 return -1;
641
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000642 if ( !(repl->entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer62423742002-07-14 19:06:20 +0000643 print_memory();
644 if (repl->nentries) {
645 if (!(repl->counters = (struct ebt_counter *)
646 malloc(repl->nentries * sizeof(struct ebt_counter))) )
647 print_memory();
648 }
649 else
650 repl->counters = NULL;
651
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000652 /* we want to receive the counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000653 repl->num_counters = repl->nentries;
654 optlen += repl->entries_size + repl->num_counters *
655 sizeof(struct ebt_counter);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000656 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000657 optname = EBT_SO_GET_INIT_ENTRIES;
658 else
659 optname = EBT_SO_GET_ENTRIES;
660 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
661 print_bug("hmm, what is wrong??? bug#1");
662
663 return 0;
664}
665
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000666int get_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000667{
668 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000669 struct ebt_replace repl;
670 struct ebt_u_entry **u_e;
671
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000672 strcpy(repl.name, u_repl->name);
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000673 if (u_repl->filename != NULL) {
Bart De Schuymer62423742002-07-14 19:06:20 +0000674 retrieve_from_file(u_repl->filename, &repl, u_repl->command);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000675 /*
676 * -L with a wrong table name should be dealt with silently
677 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000678 strcpy(u_repl->name, repl.name);
679 } else if (retrieve_from_kernel(&repl, u_repl->command) == -1)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000680 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000681
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000682 /* translate the struct ebt_replace to a struct ebt_u_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000683 u_repl->valid_hooks = repl.valid_hooks;
684 u_repl->nentries = repl.nentries;
685 u_repl->num_counters = repl.num_counters;
686 u_repl->counters = repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000687 u_repl->udc = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000688 hook = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000689 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
690 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000691 i = 0; /* holds the expected nr. of entries for the chain */
692 j = 0; /* holds the up to now counted entries for the chain */
693 /*
694 * holds the total nr. of entries,
695 * should equal u_repl->nentries afterwards
696 */
697 k = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000698 hook = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000699 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000700 &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks, repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000701 if (k != u_repl->nentries)
702 print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000703 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000704}