blob: af00fa28edc619a21f5f9eff61c26fb9500c094a [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
Bart De Schuymerf81c2702003-07-23 21:07:04 +000026#ifdef KERNEL_64_USERSPACE_32
27#define sparc_cast (uint64_t)
28#else
29#define sparc_cast
30#endif
31
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000032int sockfd = -1;
33
Bart De Schuymer62423742002-07-14 19:06:20 +000034static void get_sockfd()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035{
36 if (sockfd == -1) {
37 sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
38 if (sockfd < 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +000039 ebt_print_error("Problem getting a socket, "
40 "you probably don't have the right "
41 "permissions");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000042 }
43}
44
45static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
46{
47 struct ebt_replace *new;
48 struct ebt_u_entry *e;
49 struct ebt_u_match_list *m_l;
50 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +000051 struct ebt_u_chain_list *cl;
52 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000053 char *p, *base;
54 int i, j;
Bart De Schuymer60332e02002-06-23 08:01:47 +000055 unsigned int entries_size = 0, *chain_offsets;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000056
57 new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
58 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +000059 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000060 new->valid_hooks = u_repl->valid_hooks;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000061 strcpy(new->name, u_repl->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000062 new->nentries = u_repl->nentries;
63 new->num_counters = u_repl->num_counters;
Bart De Schuymerf81c2702003-07-23 21:07:04 +000064 new->counters = sparc_cast u_repl->counters;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +000065 /* determine nr of udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +000066 i = 0;
67 cl = u_repl->udc;
68 while (cl) {
69 i++;
70 cl = cl->next;
71 }
72 i += NF_BR_NUMHOOKS;
73 chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +000074 /* determine size */
Bart De Schuymer60332e02002-06-23 08:01:47 +000075 i = 0;
76 cl = u_repl->udc;
77 while (1) {
78 if (i < NF_BR_NUMHOOKS) {
79 if (!(new->valid_hooks & (1 << i))) {
80 i++;
81 continue;
82 }
83 entries = u_repl->hook_entry[i];
84 } else {
85 if (!cl)
86 break;
87 entries = cl->udc;
88 }
89 chain_offsets[i] = entries_size;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000090 entries_size += sizeof(struct ebt_entries);
91 j = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +000092 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000093 while (e) {
94 j++;
95 entries_size += sizeof(struct ebt_entry);
96 m_l = e->m_list;
97 while (m_l) {
98 entries_size += m_l->m->match_size +
99 sizeof(struct ebt_entry_match);
100 m_l = m_l->next;
101 }
102 w_l = e->w_list;
103 while (w_l) {
104 entries_size += w_l->w->watcher_size +
105 sizeof(struct ebt_entry_watcher);
106 w_l = w_l->next;
107 }
108 entries_size += e->t->target_size +
109 sizeof(struct ebt_entry_target);
110 e = e->next;
111 }
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000112 /* a little sanity check */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000113 if (j != entries->nentries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000114 ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000115 entries->nentries, entries->name);
116 if (i >= NF_BR_NUMHOOKS)
117 cl = cl->next;
118 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000119 }
120
121 new->entries_size = entries_size;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000122 p = (char *)malloc(entries_size);
123 if (!p)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000124 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000125
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000126 /* put everything in one block */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000127 new->entries = sparc_cast p;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000128 i = 0;
129 cl = u_repl->udc;
130 while (1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000131 struct ebt_entries *hlp;
132
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000133 hlp = (struct ebt_entries *)p;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000134 if (i < NF_BR_NUMHOOKS) {
135 if (!(new->valid_hooks & (1 << i))) {
136 i++;
137 continue;
138 }
139 entries = u_repl->hook_entry[i];
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000140 new->hook_entry[i] = sparc_cast hlp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000141 } else {
142 if (!cl)
143 break;
144 entries = cl->udc;
145 }
146 hlp->nentries = entries->nentries;
147 hlp->policy = entries->policy;
148 strcpy(hlp->name, entries->name);
149 hlp->counter_offset = entries->counter_offset;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000150 hlp->distinguisher = 0; /* make the kernel see the light */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000151 p += sizeof(struct ebt_entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000152 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000153 while (e) {
154 struct ebt_entry *tmp = (struct ebt_entry *)p;
155
156 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
157 tmp->invflags = e->invflags;
158 tmp->ethproto = e->ethproto;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000159 strcpy(tmp->in, e->in);
160 strcpy(tmp->out, e->out);
161 strcpy(tmp->logical_in, e->logical_in);
162 strcpy(tmp->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000163 memcpy(tmp->sourcemac, e->sourcemac,
164 sizeof(tmp->sourcemac));
165 memcpy(tmp->sourcemsk, e->sourcemsk,
166 sizeof(tmp->sourcemsk));
167 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
168 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
169
170 base = p;
171 p += sizeof(struct ebt_entry);
172 m_l = e->m_list;
173 while (m_l) {
174 memcpy(p, m_l->m, m_l->m->match_size +
175 sizeof(struct ebt_entry_match));
176 p += m_l->m->match_size +
177 sizeof(struct ebt_entry_match);
178 m_l = m_l->next;
179 }
180 tmp->watchers_offset = p - base;
181 w_l = e->w_list;
182 while (w_l) {
183 memcpy(p, w_l->w, w_l->w->watcher_size +
184 sizeof(struct ebt_entry_watcher));
185 p += w_l->w->watcher_size +
186 sizeof(struct ebt_entry_watcher);
187 w_l = w_l->next;
188 }
189 tmp->target_offset = p - base;
190 memcpy(p, e->t, e->t->target_size +
191 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000192 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
193 struct ebt_standard_target *st =
194 (struct ebt_standard_target *)p;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000195 /* translate the jump to a udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000196 if (st->verdict >= 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000197 st->verdict = chain_offsets
198 [st->verdict + NF_BR_NUMHOOKS];
Bart De Schuymer60332e02002-06-23 08:01:47 +0000199 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000200 p += e->t->target_size +
201 sizeof(struct ebt_entry_target);
202 tmp->next_offset = p - base;
203 e = e->next;
204 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000205 if (i >= NF_BR_NUMHOOKS)
206 cl = cl->next;
207 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000208 }
209
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000210 /* sanity check */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000211 if (p - (char *)new->entries != new->entries_size)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000212 ebt_print_bug("Entries_size bug");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000213 free(chain_offsets);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000214 return new;
215}
216
Bart De Schuymer62423742002-07-14 19:06:20 +0000217static void store_table_in_file(char *filename, struct ebt_replace *repl)
218{
219 char *command, *data;
220 int size;
221 FILE *file;
222
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000223 /* start from an empty file with right priviliges */
Bart De Schuymer62423742002-07-14 19:06:20 +0000224 command = (char *)malloc(strlen(filename) + 15);
225 if (!command)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000226 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000227 strcpy(command, "cat /dev/null>");
228 strcpy(command + 14, filename);
229 if (system(command))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000230 ebt_print_error("Couldn't create file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000231 strcpy(command, "chmod 600 ");
232 strcpy(command + 10, filename);
233 if (system(command))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000234 ebt_print_error("Couldn't chmod file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000235 free(command);
236
237 size = sizeof(struct ebt_replace) + repl->entries_size +
238 repl->nentries * sizeof(struct ebt_counter);
239 data = (char *)malloc(size);
240 if (!data)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000241 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000242 memcpy(data, repl, sizeof(struct ebt_replace));
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000243 memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries,
Bart De Schuymer62423742002-07-14 19:06:20 +0000244 repl->entries_size);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000245 /* initialize counters to zero, deliver_counters() can update them */
Bart De Schuymer62423742002-07-14 19:06:20 +0000246 memset(data + sizeof(struct ebt_replace) + repl->entries_size,
247 0, repl->nentries * sizeof(struct ebt_counter));
248 if (!(file = fopen(filename, "wb")))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000249 ebt_print_error("Couldn't open file %s", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000250 if (fwrite(data, sizeof(char), size, file) != size) {
251 fclose(file);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000252 ebt_print_error("Couldn't write everything to file %s",
253 filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000254 }
255 fclose(file);
256 free(data);
257}
258
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000259void ebt_deliver_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000260{
261 socklen_t optlen;
262 struct ebt_replace *repl;
263
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000264 /* translate the struct ebt_u_replace to a struct ebt_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000265 repl = translate_user2kernel(u_repl);
Bart De Schuymer62423742002-07-14 19:06:20 +0000266 if (u_repl->filename != NULL) {
267 store_table_in_file(u_repl->filename, repl);
268 return;
269 }
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000270 /* give the data to the kernel */
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000271 optlen = sizeof(struct ebt_replace) + repl->entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000272 get_sockfd();
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000273 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
274 return;
275 if (u_repl->command == 8) { /* the ebtables module may not
276 * yet be loaded with --atomic-commit */
277 ebtables_insmod("ebtables");
278 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES,
279 repl, optlen))
280 return;
281 }
282
Bart De Schuymer64182a32004-01-21 20:39:54 +0000283 ebt_print_error("The kernel doesn't support a certain ebtables"
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000284 " extension, consider recompiling your kernel or insmod"
285 " the extension");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000286}
287
Bart De Schuymer62423742002-07-14 19:06:20 +0000288static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
289{
290 int size = repl->nentries * sizeof(struct ebt_counter);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000291 unsigned int entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000292 struct ebt_replace hlp;
293 FILE *file;
294
295 if (!(file = fopen(filename, "r+b")))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000296 ebt_print_error("Could not open file %s", filename);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000297 /*
298 * find out entries_size and then set the file pointer to the
299 * counters
300 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000301 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
302 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
303 sizeof(unsigned int) ||
304 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
305 fclose(file);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000306 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000307 }
308 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
309 fclose(file);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000310 ebt_print_error("Could not write everything to file %s",
311 filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000312 }
313 fclose(file);
314}
315
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000316/* gets executed after ebt_deliver_table */
317void ebt_deliver_counters(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000318{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000319 struct ebt_counter *old, *new, *newcounters;
320 socklen_t optlen;
321 struct ebt_replace repl;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000322 struct ebt_cntchanges *cc = u_repl->counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000323
324 if (u_repl->nentries == 0)
325 return;
326
327 newcounters = (struct ebt_counter *)
328 malloc(u_repl->nentries * sizeof(struct ebt_counter));
329 if (!newcounters)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000330 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000331 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
332 old = u_repl->counters;
333 new = newcounters;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000334 while (cc) {
335 if (cc->type == CNT_NORM) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000336 /*
337 *'normal' rule, meaning we didn't do anything to it
338 * So, we just copy
339 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000340 new->pcnt = old->pcnt;
Bart De Schuymer6d06d262003-05-01 19:38:54 +0000341 new->bcnt = old->bcnt;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000342 /* we've used an old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000343 old++;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000344 /* we've set a new counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000345 new++;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000346 } else if (cc->type == CNT_DEL) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000347 /* don't use this old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000348 old++;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000349 } else if (cc->type == CNT_ADD) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000350 /* new counter, let it stay 0 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000351 new++;
352 } else {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000353 /* zero it (let it stay 0) */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000354 old++;
355 new++;
356 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000357 cc = cc->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000358 }
359
360 free(u_repl->counters);
361 u_repl->counters = newcounters;
362 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000363 if (u_repl->filename != NULL) {
364 store_counters_in_file(u_repl->filename, u_repl);
365 return;
366 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000367 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
368 sizeof(struct ebt_replace);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000369 /* now put the stuff in the kernel's struct ebt_replace */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000370 repl.counters = sparc_cast u_repl->counters;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000371 repl.num_counters = u_repl->num_counters;
372 memcpy(repl.name, u_repl->name, sizeof(repl.name));
373
374 get_sockfd();
375 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000376 ebt_print_bug("Couldn't update kernel counters");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000377}
378
379static int
380ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
381{
382 struct ebt_u_match_list *new;
383
384 new = (struct ebt_u_match_list *)
385 malloc(sizeof(struct ebt_u_match_list));
386 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000387 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000388 new->m = (struct ebt_entry_match *)
389 malloc(m->match_size + sizeof(struct ebt_entry_match));
390 if (!new->m)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000391 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000392 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
393 new->next = NULL;
394 **l = new;
395 *l = &new->next;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000396 if (ebt_find_match(new->m->u.name) == NULL)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000397 ebt_print_error("Kernel match %s unsupported by userspace tool",
398 new->m->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000399 return 0;
400}
401
402static int
403ebt_translate_watcher(struct ebt_entry_watcher *w,
404 struct ebt_u_watcher_list ***l)
405{
406 struct ebt_u_watcher_list *new;
407
408 new = (struct ebt_u_watcher_list *)
409 malloc(sizeof(struct ebt_u_watcher_list));
410 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000411 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000412 new->w = (struct ebt_entry_watcher *)
413 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
414 if (!new->w)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000415 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000416 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
417 new->next = NULL;
418 **l = new;
419 *l = &new->next;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000420 if (ebt_find_watcher(new->w->u.name) == NULL)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000421 ebt_print_error("Kernel watcher %s unsupported by userspace "
422 "tool", new->w->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000423 return 0;
424}
425
426static int
427ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
428 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000429 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000430{
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000431 /* an entry */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000432 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
433 struct ebt_u_entry *new;
434 struct ebt_u_match_list **m_l;
435 struct ebt_u_watcher_list **w_l;
436 struct ebt_entry_target *t;
437
438 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
439 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000440 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000441 new->bitmask = e->bitmask;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000442 /*
443 * plain userspace code doesn't know about
444 * EBT_ENTRY_OR_ENTRIES
445 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000446 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
447 new->invflags = e->invflags;
448 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000449 strcpy(new->in, e->in);
450 strcpy(new->out, e->out);
451 strcpy(new->logical_in, e->logical_in);
452 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000453 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
454 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
455 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
456 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
457 new->m_list = NULL;
458 new->w_list = NULL;
459 new->next = NULL;
460 m_l = &new->m_list;
461 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
462 w_l = &new->w_list;
463 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
464
465 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
466 new->t = (struct ebt_entry_target *)
467 malloc(t->target_size + sizeof(struct ebt_entry_target));
468 if (!new->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000469 ebt_print_memory();
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000470 if (ebt_find_target(t->u.name) == NULL)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000471 ebt_print_error("Kernel target %s unsupported by "
472 "userspace tool", t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000473 memcpy(new->t, t, t->target_size +
474 sizeof(struct ebt_entry_target));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000475 /* deal with jumps to udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000476 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
477 char *tmp = base;
478 int verdict = ((struct ebt_standard_target *)t)->verdict;
479 int i;
480 struct ebt_u_chain_list *cl;
481
482 if (verdict >= 0) {
483 tmp += verdict;
484 cl = u_repl->udc;
485 i = 0;
486 while (cl && cl->kernel_start != tmp) {
487 i++;
488 cl = cl->next;
489 }
490 if (!cl)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000491 ebt_print_bug("can't find udc for "
492 "jump");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000493 ((struct ebt_standard_target *)new->t)->verdict = i;
494 }
495 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000496
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000497 /* I love pointers */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000498 **u_e = new;
499 *u_e = &new->next;
500 (*cnt)++;
501 (*totalcnt)++;
502 return 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000503 } else { /* a new chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000504 int i;
505 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000506 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000507
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000508 if (*n != *cnt)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000509 ebt_print_bug("Nr of entries in the chain is wrong");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000510 *n = entries->nentries;
511 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000512 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
513 if (valid_hooks & (1 << i))
514 break;
515 *hook = i;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000516 /* makes use of fact that standard chains come before udc */
517 if (i >= NF_BR_NUMHOOKS) { /* udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000518 i -= NF_BR_NUMHOOKS;
519 cl = u_repl->udc;
520 while (i-- > 0)
521 cl = cl->next;
522 *u_e = &(cl->udc->entries);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000523 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000524 *u_e = &(u_repl->hook_entry[*hook]->entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000525 return 0;
526 }
527}
528
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000529/* initialize all chain headers */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000530static int
531ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
532 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
533{
534 int i;
535 struct ebt_entries *entries = (struct ebt_entries *)e;
536 struct ebt_u_entries *new;
537 struct ebt_u_chain_list **chain_list;
538
539 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
540 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
541 if (valid_hooks & (1 << i))
542 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000543 /* makes use of fact that standard chains come before udc */
544 if (i >= NF_BR_NUMHOOKS) { /* udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000545 chain_list = &u_repl->udc;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000546 /* add in the back */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000547 while (*chain_list)
548 chain_list = &((*chain_list)->next);
549 *chain_list = (struct ebt_u_chain_list *)
550 malloc(sizeof(struct ebt_u_chain_list));
551 if (!(*chain_list))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000552 ebt_print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000553 (*chain_list)->next = NULL;
554 (*chain_list)->udc = (struct ebt_u_entries *)
555 malloc(sizeof(struct ebt_u_entries));
556 if (!((*chain_list)->udc))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000557 ebt_print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000558 new = (*chain_list)->udc;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000559 /*
560 * ebt_translate_entry depends on this for knowing
561 * to which chain is being jumped
562 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000563 (*chain_list)->kernel_start = (char *)e;
564 } else {
565 *hook = i;
566 new = (struct ebt_u_entries *)
567 malloc(sizeof(struct ebt_u_entries));
568 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000569 ebt_print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000570 u_repl->hook_entry[*hook] = new;
571 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000572 new->nentries = entries->nentries;
573 new->policy = entries->policy;
574 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000575 new->counter_offset = entries->counter_offset;
576 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000577 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000578 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000579}
580
Bart De Schuymer62423742002-07-14 19:06:20 +0000581static void retrieve_from_file(char *filename, struct ebt_replace *repl,
582 char command)
583{
584 FILE *file;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000585 char *hlp = NULL, *entries;
586 struct ebt_counter *counters;
Bart De Schuymer62423742002-07-14 19:06:20 +0000587 int size;
588
589 if (!(file = fopen(filename, "r+b")))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000590 ebt_print_error("Could not open file %s", filename);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000591 /*
592 * make sure table name is right if command isn't -L or --atomic-commit
593 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000594 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000595 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000596 if (!hlp)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000597 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000598 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000599 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000600 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
601 != sizeof(struct ebt_replace))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000602 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000603 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
604 fclose(file);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000605 ebt_print_error("File %s contains wrong table name or is "
606 "corrupt", filename);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000607 free(hlp);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000608 } else if (!ebt_find_table(repl->name)) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000609 fclose(file);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000610 ebt_print_error("File %s contains invalid table name",
611 filename);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000612 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000613
Bart De Schuymer62423742002-07-14 19:06:20 +0000614 size = sizeof(struct ebt_replace) +
615 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
616 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000617 if (size != ftell(file)) {
618 fclose(file);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000619 ebt_print_error("File %s has wrong size", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000620 }
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000621 entries = (char *)malloc(repl->entries_size);
622 if (!entries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000623 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000624 repl->entries = sparc_cast entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000625 if (repl->nentries) {
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000626 counters = (struct ebt_counter *)
Bart De Schuymer62423742002-07-14 19:06:20 +0000627 malloc(repl->nentries * sizeof(struct ebt_counter));
Bart De Schuymer8e96bee2003-08-27 16:59:39 +0000628 repl->counters = sparc_cast counters;
Bart De Schuymer62423742002-07-14 19:06:20 +0000629 if (!repl->counters)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000630 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000631 } else
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000632 repl->counters = sparc_cast NULL;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000633 /* copy entries and counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000634 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000635 fread((char *)repl->entries, sizeof(char), repl->entries_size, file)
Bart De Schuymer62423742002-07-14 19:06:20 +0000636 != repl->entries_size ||
Bart De Schuymer64182a32004-01-21 20:39:54 +0000637 fseek(file, sizeof(struct ebt_replace) + repl->entries_size,
638 SEEK_SET)
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000639 || fread((char *)repl->counters, sizeof(char),
Bart De Schuymer62423742002-07-14 19:06:20 +0000640 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000641 != repl->nentries * sizeof(struct ebt_counter)) {
642 fclose(file);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000643 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000644 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000645 fclose(file);
646}
647
Bart De Schuymer64182a32004-01-21 20:39:54 +0000648static int retrieve_from_kernel(struct ebt_replace *repl, char command,
649 int init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000650{
651 socklen_t optlen;
652 int optname;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000653 char *entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000654
655 optlen = sizeof(struct ebt_replace);
656 get_sockfd();
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000657 /* --atomic-init || --init-table */
Bart De Schuymer64182a32004-01-21 20:39:54 +0000658 if (init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000659 optname = EBT_SO_GET_INIT_INFO;
660 else
661 optname = EBT_SO_GET_INFO;
662 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
663 return -1;
664
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000665 if ( !(entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer64182a32004-01-21 20:39:54 +0000666 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000667 repl->entries = sparc_cast entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000668 if (repl->nentries) {
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000669 struct ebt_counter *counters;
670
671 if (!(counters = (struct ebt_counter *)
Bart De Schuymer62423742002-07-14 19:06:20 +0000672 malloc(repl->nentries * sizeof(struct ebt_counter))) )
Bart De Schuymer64182a32004-01-21 20:39:54 +0000673 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000674 repl->counters = sparc_cast counters;
Bart De Schuymer62423742002-07-14 19:06:20 +0000675 }
676 else
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000677 repl->counters = sparc_cast NULL;
Bart De Schuymer62423742002-07-14 19:06:20 +0000678
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000679 /* we want to receive the counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000680 repl->num_counters = repl->nentries;
681 optlen += repl->entries_size + repl->num_counters *
682 sizeof(struct ebt_counter);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000683 if (init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000684 optname = EBT_SO_GET_INIT_ENTRIES;
685 else
686 optname = EBT_SO_GET_ENTRIES;
687 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000688 ebt_print_bug("hmm, what is wrong??? bug#1");
Bart De Schuymer62423742002-07-14 19:06:20 +0000689
690 return 0;
691}
692
Bart De Schuymer64182a32004-01-21 20:39:54 +0000693int ebt_get_table(struct ebt_u_replace *u_repl, int init)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000694{
695 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000696 struct ebt_replace repl;
697 struct ebt_u_entry **u_e;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000698 struct ebt_cntchanges *new_cc;
699 struct ebt_cntchanges **prev_cc = &(u_repl->counterchanges);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000700
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000701 strcpy(repl.name, u_repl->name);
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000702 if (u_repl->filename != NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000703 if (init)
704 ebt_print_bug("getting initial table data from a "
705 "file is impossible");
Bart De Schuymer62423742002-07-14 19:06:20 +0000706 retrieve_from_file(u_repl->filename, &repl, u_repl->command);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000707 /*
708 * -L with a wrong table name should be dealt with silently
709 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000710 strcpy(u_repl->name, repl.name);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000711 } else if (retrieve_from_kernel(&repl, u_repl->command, init) == -1)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000712 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000713
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000714 /* translate the struct ebt_replace to a struct ebt_u_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000715 u_repl->valid_hooks = repl.valid_hooks;
716 u_repl->nentries = repl.nentries;
717 u_repl->num_counters = repl.num_counters;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000718 u_repl->counters = (struct ebt_counter *)repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000719 u_repl->udc = NULL;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000720 u_repl->counterchanges = NULL;
721 for (i = 0; i < repl.nentries; i++) {
722 new_cc = (struct ebt_cntchanges *)
723 malloc(sizeof(struct ebt_cntchanges));
724 if (!new_cc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000725 ebt_print_memory();
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000726 new_cc->type = CNT_NORM;
727 new_cc->next = NULL;
728 *prev_cc = new_cc;
729 prev_cc = &(new_cc->next);
730 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000731 hook = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000732 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
733 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000734 i = 0; /* holds the expected nr. of entries for the chain */
735 j = 0; /* holds the up to now counted entries for the chain */
736 /*
737 * holds the total nr. of entries,
738 * should equal u_repl->nentries afterwards
739 */
740 k = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000741 hook = -1;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000742 EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size,
743 ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl,
744 u_repl->valid_hooks, (char *)repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000745 if (k != u_repl->nentries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000746 ebt_print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000747 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000748}