blob: 70f5ff8f1a32b01a760544d1fd1e730396484fe9 [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 Schuymer9895a8e2003-01-11 10:14:24 +0000326 /* we've used an old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000327 old++;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000328 /* we've set a new counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000329 new++;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000330 } else if (*point == CNT_DEL) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000331 /* don't use this old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000332 old++;
333 } else if (*point == CNT_ADD) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000334 /* new counter, let it stay 0 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000335 new++;
336 } else {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000337 /* zero it (let it stay 0) */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000338 old++;
339 new++;
340 }
341 point++;
342 }
343
344 free(u_repl->counters);
345 u_repl->counters = newcounters;
346 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000347 if (u_repl->filename != NULL) {
348 store_counters_in_file(u_repl->filename, u_repl);
349 return;
350 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000351 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
352 sizeof(struct ebt_replace);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000353 /* now put the stuff in the kernel's struct ebt_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000354 repl.counters = u_repl->counters;
355 repl.num_counters = u_repl->num_counters;
356 memcpy(repl.name, u_repl->name, sizeof(repl.name));
357
358 get_sockfd();
359 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000360 print_bug("Couldn't update kernel counters");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000361}
362
363static int
364ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
365{
366 struct ebt_u_match_list *new;
367
368 new = (struct ebt_u_match_list *)
369 malloc(sizeof(struct ebt_u_match_list));
370 if (!new)
371 print_memory();
372 new->m = (struct ebt_entry_match *)
373 malloc(m->match_size + sizeof(struct ebt_entry_match));
374 if (!new->m)
375 print_memory();
376 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
377 new->next = NULL;
378 **l = new;
379 *l = &new->next;
380 if (find_match(new->m->u.name) == NULL)
381 print_error("Kernel match %s unsupported by userspace tool",
382 new->m->u.name);
383 return 0;
384}
385
386static int
387ebt_translate_watcher(struct ebt_entry_watcher *w,
388 struct ebt_u_watcher_list ***l)
389{
390 struct ebt_u_watcher_list *new;
391
392 new = (struct ebt_u_watcher_list *)
393 malloc(sizeof(struct ebt_u_watcher_list));
394 if (!new)
395 print_memory();
396 new->w = (struct ebt_entry_watcher *)
397 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
398 if (!new->w)
399 print_memory();
400 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
401 new->next = NULL;
402 **l = new;
403 *l = &new->next;
404 if (find_watcher(new->w->u.name) == NULL)
405 print_error("Kernel watcher %s unsupported by userspace tool",
406 new->w->u.name);
407 return 0;
408}
409
410static int
411ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
412 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000413 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000414{
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000415 /* an entry */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000416 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
417 struct ebt_u_entry *new;
418 struct ebt_u_match_list **m_l;
419 struct ebt_u_watcher_list **w_l;
420 struct ebt_entry_target *t;
421
422 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
423 if (!new)
424 print_memory();
425 new->bitmask = e->bitmask;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000426 /*
427 * plain userspace code doesn't know about
428 * EBT_ENTRY_OR_ENTRIES
429 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000430 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
431 new->invflags = e->invflags;
432 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000433 strcpy(new->in, e->in);
434 strcpy(new->out, e->out);
435 strcpy(new->logical_in, e->logical_in);
436 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000437 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
438 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
439 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
440 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
441 new->m_list = NULL;
442 new->w_list = NULL;
443 new->next = NULL;
444 m_l = &new->m_list;
445 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
446 w_l = &new->w_list;
447 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
448
449 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
450 new->t = (struct ebt_entry_target *)
451 malloc(t->target_size + sizeof(struct ebt_entry_target));
452 if (!new->t)
453 print_memory();
454 if (find_target(t->u.name) == NULL)
455 print_error("Kernel target %s unsupported by "
456 "userspace tool", t->u.name);
457 memcpy(new->t, t, t->target_size +
458 sizeof(struct ebt_entry_target));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000459 /* deal with jumps to udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000460 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
461 char *tmp = base;
462 int verdict = ((struct ebt_standard_target *)t)->verdict;
463 int i;
464 struct ebt_u_chain_list *cl;
465
466 if (verdict >= 0) {
467 tmp += verdict;
468 cl = u_repl->udc;
469 i = 0;
470 while (cl && cl->kernel_start != tmp) {
471 i++;
472 cl = cl->next;
473 }
474 if (!cl)
475 print_bug("can't find udc for jump");
476 ((struct ebt_standard_target *)new->t)->verdict = i;
477 }
478 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000479
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000480 /* I love pointers */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000481 **u_e = new;
482 *u_e = &new->next;
483 (*cnt)++;
484 (*totalcnt)++;
485 return 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000486 } else { /* a new chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000487 int i;
488 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000489 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000490
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000491 if (*n != *cnt)
492 print_bug("Nr of entries in the chain is wrong");
493 *n = entries->nentries;
494 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000495 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
496 if (valid_hooks & (1 << i))
497 break;
498 *hook = i;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000499 /* makes use of fact that standard chains come before udc */
500 if (i >= NF_BR_NUMHOOKS) { /* udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000501 i -= NF_BR_NUMHOOKS;
502 cl = u_repl->udc;
503 while (i-- > 0)
504 cl = cl->next;
505 *u_e = &(cl->udc->entries);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000506 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000507 *u_e = &(u_repl->hook_entry[*hook]->entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000508 return 0;
509 }
510}
511
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000512/* initialize all chain headers */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000513static int
514ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
515 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
516{
517 int i;
518 struct ebt_entries *entries = (struct ebt_entries *)e;
519 struct ebt_u_entries *new;
520 struct ebt_u_chain_list **chain_list;
521
522 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
523 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
524 if (valid_hooks & (1 << i))
525 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000526 /* makes use of fact that standard chains come before udc */
527 if (i >= NF_BR_NUMHOOKS) { /* udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000528 chain_list = &u_repl->udc;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000529 /* add in the back */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000530 while (*chain_list)
531 chain_list = &((*chain_list)->next);
532 *chain_list = (struct ebt_u_chain_list *)
533 malloc(sizeof(struct ebt_u_chain_list));
534 if (!(*chain_list))
535 print_memory();
536 (*chain_list)->next = NULL;
537 (*chain_list)->udc = (struct ebt_u_entries *)
538 malloc(sizeof(struct ebt_u_entries));
539 if (!((*chain_list)->udc))
540 print_memory();
541 new = (*chain_list)->udc;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000542 /*
543 * ebt_translate_entry depends on this for knowing
544 * to which chain is being jumped
545 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000546 (*chain_list)->kernel_start = (char *)e;
547 } else {
548 *hook = i;
549 new = (struct ebt_u_entries *)
550 malloc(sizeof(struct ebt_u_entries));
551 if (!new)
552 print_memory();
553 u_repl->hook_entry[*hook] = new;
554 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000555 new->nentries = entries->nentries;
556 new->policy = entries->policy;
557 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000558 new->counter_offset = entries->counter_offset;
559 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000560 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000561 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000562}
563
Bart De Schuymer62423742002-07-14 19:06:20 +0000564static void retrieve_from_file(char *filename, struct ebt_replace *repl,
565 char command)
566{
567 FILE *file;
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000568 char *hlp = NULL;
Bart De Schuymer62423742002-07-14 19:06:20 +0000569 int size;
570
571 if (!(file = fopen(filename, "r+b")))
572 print_error("Could not open file %s", filename);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000573 /*
574 * make sure table name is right if command isn't -L or --atomic-commit
575 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000576 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000577 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000578 if (!hlp)
579 print_memory();
580 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000581 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000582 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
583 != sizeof(struct ebt_replace))
584 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000585 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
586 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000587 print_error("File %s contains wrong table name or is corrupt",
588 filename);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000589 free(hlp);
590 } else if (!find_table(repl->name)) {
591 fclose(file);
592 print_error("File %s contains invalid table name", filename);
593 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000594
Bart De Schuymer62423742002-07-14 19:06:20 +0000595 size = sizeof(struct ebt_replace) +
596 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
597 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000598 if (size != ftell(file)) {
599 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000600 print_error("File %s has wrong size", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000601 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000602 repl->entries = (char *)malloc(repl->entries_size);
603 if (!repl->entries)
604 print_memory();
605 if (repl->nentries) {
606 repl->counters = (struct ebt_counter *)
607 malloc(repl->nentries * sizeof(struct ebt_counter));
608 if (!repl->counters)
609 print_memory();
610 } else
611 repl->counters = NULL;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000612 /* copy entries and counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000613 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
614 fread(repl->entries, sizeof(char), repl->entries_size, file)
615 != repl->entries_size ||
616 fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
617 || fread(repl->counters, sizeof(char),
618 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000619 != repl->nentries * sizeof(struct ebt_counter)) {
620 fclose(file);
Bart De Schuymer62423742002-07-14 19:06:20 +0000621 print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000622 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000623 fclose(file);
624}
625
626static int retrieve_from_kernel(struct ebt_replace *repl, char command)
627{
628 socklen_t optlen;
629 int optname;
630
631 optlen = sizeof(struct ebt_replace);
632 get_sockfd();
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000633 /* --atomic-init || --init-table */
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000634 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000635 optname = EBT_SO_GET_INIT_INFO;
636 else
637 optname = EBT_SO_GET_INFO;
638 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
639 return -1;
640
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000641 if ( !(repl->entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer62423742002-07-14 19:06:20 +0000642 print_memory();
643 if (repl->nentries) {
644 if (!(repl->counters = (struct ebt_counter *)
645 malloc(repl->nentries * sizeof(struct ebt_counter))) )
646 print_memory();
647 }
648 else
649 repl->counters = NULL;
650
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000651 /* we want to receive the counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000652 repl->num_counters = repl->nentries;
653 optlen += repl->entries_size + repl->num_counters *
654 sizeof(struct ebt_counter);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000655 if (command == 7 || command == 11)
Bart De Schuymer62423742002-07-14 19:06:20 +0000656 optname = EBT_SO_GET_INIT_ENTRIES;
657 else
658 optname = EBT_SO_GET_ENTRIES;
659 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
660 print_bug("hmm, what is wrong??? bug#1");
661
662 return 0;
663}
664
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000665int get_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000666{
667 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000668 struct ebt_replace repl;
669 struct ebt_u_entry **u_e;
670
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000671 strcpy(repl.name, u_repl->name);
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000672 if (u_repl->filename != NULL) {
Bart De Schuymer62423742002-07-14 19:06:20 +0000673 retrieve_from_file(u_repl->filename, &repl, u_repl->command);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000674 /*
675 * -L with a wrong table name should be dealt with silently
676 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000677 strcpy(u_repl->name, repl.name);
678 } else if (retrieve_from_kernel(&repl, u_repl->command) == -1)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000679 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000680
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000681 /* translate the struct ebt_replace to a struct ebt_u_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000682 u_repl->valid_hooks = repl.valid_hooks;
683 u_repl->nentries = repl.nentries;
684 u_repl->num_counters = repl.num_counters;
685 u_repl->counters = repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000686 u_repl->udc = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000687 hook = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000688 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
689 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000690 i = 0; /* holds the expected nr. of entries for the chain */
691 j = 0; /* holds the up to now counted entries for the chain */
692 /*
693 * holds the total nr. of entries,
694 * should equal u_repl->nentries afterwards
695 */
696 k = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000697 hook = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000698 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000699 &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks, repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000700 if (k != u_repl->nentries)
701 print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000702 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000703}