blob: f9f173b4da40913823840a1107e41e55a785e44c [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 Schuymer6622a012005-01-19 21:09:05 +000034static int get_sockfd()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035{
Bart De Schuymer6622a012005-01-19 21:09:05 +000036 int ret = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000037 if (sockfd == -1) {
38 sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
Bart De Schuymer6622a012005-01-19 21:09:05 +000039 if (sockfd < 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +000040 ebt_print_error("Problem getting a socket, "
41 "you probably don't have the right "
42 "permissions");
Bart De Schuymer6622a012005-01-19 21:09:05 +000043 ret = -1;
44 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000045 }
Bart De Schuymer6622a012005-01-19 21:09:05 +000046 return ret;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000047}
48
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +000049static struct ebt_replace *translate_user2kernel(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000050{
51 struct ebt_replace *new;
52 struct ebt_u_entry *e;
53 struct ebt_u_match_list *m_l;
54 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +000055 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000056 char *p, *base;
57 int i, j;
Bart De Schuymer60332e02002-06-23 08:01:47 +000058 unsigned int entries_size = 0, *chain_offsets;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000059
60 new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
61 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +000062 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000063 new->valid_hooks = u_repl->valid_hooks;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000064 strcpy(new->name, u_repl->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000065 new->nentries = u_repl->nentries;
66 new->num_counters = u_repl->num_counters;
Bart De Schuymerf81c2702003-07-23 21:07:04 +000067 new->counters = sparc_cast u_repl->counters;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +000068 chain_offsets = (unsigned int *)malloc(u_repl->num_chains * sizeof(unsigned int));
Bart De Schuymer6622a012005-01-19 21:09:05 +000069 /* Determine size */
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +000070 for (i = 0; i < u_repl->num_chains; i++) {
71 if (!(entries = u_repl->chains[i]))
72 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +000073 chain_offsets[i] = entries_size;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000074 entries_size += sizeof(struct ebt_entries);
75 j = 0;
Bart De Schuymere94eaf72005-08-28 16:06:22 +000076 e = entries->entries->next;
77 while (e != entries->entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000078 j++;
79 entries_size += sizeof(struct ebt_entry);
80 m_l = e->m_list;
81 while (m_l) {
82 entries_size += m_l->m->match_size +
83 sizeof(struct ebt_entry_match);
84 m_l = m_l->next;
85 }
86 w_l = e->w_list;
87 while (w_l) {
88 entries_size += w_l->w->watcher_size +
89 sizeof(struct ebt_entry_watcher);
90 w_l = w_l->next;
91 }
92 entries_size += e->t->target_size +
93 sizeof(struct ebt_entry_target);
94 e = e->next;
95 }
Bart De Schuymer6622a012005-01-19 21:09:05 +000096 /* A little sanity check */
Bart De Schuymer60332e02002-06-23 08:01:47 +000097 if (j != entries->nentries)
Bart De Schuymer64182a32004-01-21 20:39:54 +000098 ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j,
Bart De Schuymer60332e02002-06-23 08:01:47 +000099 entries->nentries, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000100 }
101
102 new->entries_size = entries_size;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000103 p = (char *)malloc(entries_size);
104 if (!p)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000105 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000106
Bart De Schuymer6622a012005-01-19 21:09:05 +0000107 /* Put everything in one block */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000108 new->entries = sparc_cast p;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000109 for (i = 0; i < u_repl->num_chains; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000110 struct ebt_entries *hlp;
111
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000112 hlp = (struct ebt_entries *)p;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000113 if (!(entries = u_repl->chains[i]))
114 continue;
115 if (i < NF_BR_NUMHOOKS)
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000116 new->hook_entry[i] = sparc_cast hlp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000117 hlp->nentries = entries->nentries;
118 hlp->policy = entries->policy;
119 strcpy(hlp->name, entries->name);
120 hlp->counter_offset = entries->counter_offset;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000121 hlp->distinguisher = 0; /* Make the kernel see the light */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000122 p += sizeof(struct ebt_entries);
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000123 e = entries->entries->next;
124 while (e != entries->entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000125 struct ebt_entry *tmp = (struct ebt_entry *)p;
126
127 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
128 tmp->invflags = e->invflags;
129 tmp->ethproto = e->ethproto;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000130 strcpy(tmp->in, e->in);
131 strcpy(tmp->out, e->out);
132 strcpy(tmp->logical_in, e->logical_in);
133 strcpy(tmp->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000134 memcpy(tmp->sourcemac, e->sourcemac,
135 sizeof(tmp->sourcemac));
136 memcpy(tmp->sourcemsk, e->sourcemsk,
137 sizeof(tmp->sourcemsk));
138 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
139 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
140
141 base = p;
142 p += sizeof(struct ebt_entry);
143 m_l = e->m_list;
144 while (m_l) {
145 memcpy(p, m_l->m, m_l->m->match_size +
146 sizeof(struct ebt_entry_match));
147 p += m_l->m->match_size +
148 sizeof(struct ebt_entry_match);
149 m_l = m_l->next;
150 }
151 tmp->watchers_offset = p - base;
152 w_l = e->w_list;
153 while (w_l) {
154 memcpy(p, w_l->w, w_l->w->watcher_size +
155 sizeof(struct ebt_entry_watcher));
156 p += w_l->w->watcher_size +
157 sizeof(struct ebt_entry_watcher);
158 w_l = w_l->next;
159 }
160 tmp->target_offset = p - base;
161 memcpy(p, e->t, e->t->target_size +
162 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000163 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
164 struct ebt_standard_target *st =
165 (struct ebt_standard_target *)p;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000166 /* Translate the jump to a udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000167 if (st->verdict >= 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000168 st->verdict = chain_offsets
169 [st->verdict + NF_BR_NUMHOOKS];
Bart De Schuymer60332e02002-06-23 08:01:47 +0000170 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000171 p += e->t->target_size +
172 sizeof(struct ebt_entry_target);
173 tmp->next_offset = p - base;
174 e = e->next;
175 }
176 }
177
Bart De Schuymer6622a012005-01-19 21:09:05 +0000178 /* Sanity check */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000179 if (p - (char *)new->entries != new->entries_size)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000180 ebt_print_bug("Entries_size bug");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000181 free(chain_offsets);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000182 return new;
183}
184
Bart De Schuymer62423742002-07-14 19:06:20 +0000185static void store_table_in_file(char *filename, struct ebt_replace *repl)
186{
187 char *command, *data;
188 int size;
189 FILE *file;
190
Bart De Schuymer6622a012005-01-19 21:09:05 +0000191 /* Start from an empty file with right priviliges */
Bart De Schuymer62423742002-07-14 19:06:20 +0000192 command = (char *)malloc(strlen(filename) + 15);
193 if (!command)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000194 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000195 strcpy(command, "cat /dev/null>");
196 strcpy(command + 14, filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000197 if (system(command)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000198 ebt_print_error("Couldn't create file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000199 goto free_command;
200 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000201 strcpy(command, "chmod 600 ");
202 strcpy(command + 10, filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000203 if (system(command)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000204 ebt_print_error("Couldn't chmod file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000205 goto free_command;
206 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000207
208 size = sizeof(struct ebt_replace) + repl->entries_size +
209 repl->nentries * sizeof(struct ebt_counter);
210 data = (char *)malloc(size);
211 if (!data)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000212 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000213 memcpy(data, repl, sizeof(struct ebt_replace));
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000214 memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries,
Bart De Schuymer62423742002-07-14 19:06:20 +0000215 repl->entries_size);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000216 /* Initialize counters to zero, deliver_counters() can update them */
Bart De Schuymer62423742002-07-14 19:06:20 +0000217 memset(data + sizeof(struct ebt_replace) + repl->entries_size,
218 0, repl->nentries * sizeof(struct ebt_counter));
Bart De Schuymer6622a012005-01-19 21:09:05 +0000219 if (!(file = fopen(filename, "wb"))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000220 ebt_print_error("Couldn't open file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000221 goto free_data;
222 } else if (fwrite(data, sizeof(char), size, file) != size)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000223 ebt_print_error("Couldn't write everything to file %s",
224 filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000225 fclose(file);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000226free_data:
Bart De Schuymer62423742002-07-14 19:06:20 +0000227 free(data);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000228free_command:
229 free(command);
Bart De Schuymer62423742002-07-14 19:06:20 +0000230}
231
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000232void ebt_deliver_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000233{
234 socklen_t optlen;
235 struct ebt_replace *repl;
236
Bart De Schuymer6622a012005-01-19 21:09:05 +0000237 /* Translate the struct ebt_u_replace to a struct ebt_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000238 repl = translate_user2kernel(u_repl);
Bart De Schuymer62423742002-07-14 19:06:20 +0000239 if (u_repl->filename != NULL) {
240 store_table_in_file(u_repl->filename, repl);
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000241 goto free_repl;
Bart De Schuymer62423742002-07-14 19:06:20 +0000242 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000243 /* Give the data to the kernel */
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000244 optlen = sizeof(struct ebt_replace) + repl->entries_size;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000245 if (get_sockfd())
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000246 goto free_repl;
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000247 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000248 goto free_repl;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000249 if (u_repl->command == 8) { /* The ebtables module may not
250 * yet be loaded with --atomic-commit */
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000251 ebtables_insmod("ebtables");
252 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES,
253 repl, optlen))
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000254 goto free_repl;
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000255 }
256
Bart De Schuymer64182a32004-01-21 20:39:54 +0000257 ebt_print_error("The kernel doesn't support a certain ebtables"
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000258 " extension, consider recompiling your kernel or insmod"
259 " the extension");
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000260free_repl:
261 if (repl) {
262 free(repl->entries);
263 free(repl);
264 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000265}
266
Bart De Schuymer6622a012005-01-19 21:09:05 +0000267static int store_counters_in_file(char *filename, struct ebt_u_replace *repl)
Bart De Schuymer62423742002-07-14 19:06:20 +0000268{
Bart De Schuymer6622a012005-01-19 21:09:05 +0000269 int size = repl->nentries * sizeof(struct ebt_counter), ret = 0;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000270 unsigned int entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000271 struct ebt_replace hlp;
272 FILE *file;
273
Bart De Schuymer6622a012005-01-19 21:09:05 +0000274 if (!(file = fopen(filename, "r+b"))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000275 ebt_print_error("Could not open file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000276 return -1;
277 }
278 /* Find out entries_size and then set the file pointer to the
279 * counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000280 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
281 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
282 sizeof(unsigned int) ||
283 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000284 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000285 ret = -1;
286 goto close_file;
Bart De Schuymer62423742002-07-14 19:06:20 +0000287 }
288 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000289 ebt_print_error("Could not write everything to file %s",
290 filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000291 ret = -1;
Bart De Schuymer62423742002-07-14 19:06:20 +0000292 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000293close_file:
Bart De Schuymer62423742002-07-14 19:06:20 +0000294 fclose(file);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000295 return 0;
Bart De Schuymer62423742002-07-14 19:06:20 +0000296}
297
Bart De Schuymer6622a012005-01-19 21:09:05 +0000298/* Gets executed after ebt_deliver_table. Delivers the counters to the kernel
299 * and resets the counterchanges to CNT_NORM */
Bart De Schuymer83a1b0f2005-09-28 19:36:17 +0000300void ebt_deliver_counters(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000301{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000302 struct ebt_counter *old, *new, *newcounters;
303 socklen_t optlen;
304 struct ebt_replace repl;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000305 struct ebt_cntchanges *cc = u_repl->cc->next, *cc2;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000306 struct ebt_u_entries *entries;
307 struct ebt_u_entry *next = NULL;
308 int i, chainnr = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000309
310 if (u_repl->nentries == 0)
311 return;
312
313 newcounters = (struct ebt_counter *)
314 malloc(u_repl->nentries * sizeof(struct ebt_counter));
315 if (!newcounters)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000316 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000317 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
318 old = u_repl->counters;
319 new = newcounters;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000320 while (cc != u_repl->cc) {
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000321 if (!next || next == entries->entries) {
322 while (chainnr < u_repl->num_chains && (!(entries = u_repl->chains[chainnr++]) ||
323 (next = entries->entries->next) == entries->entries));
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000324 if (chainnr == u_repl->num_chains)
325 break;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000326 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000327 if (cc->type == CNT_NORM) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000328 /* 'Normal' rule, meaning we didn't do anything to it
329 * So, we just copy */
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000330 *new = *old;
Bart De Schuymerab611e22005-02-14 20:20:03 +0000331 next->cnt = *new;
332 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000333 old++; /* We've used an old counter */
334 new++; /* We've set a new counter */
Bart De Schuymerff587202005-02-08 20:02:28 +0000335 next = next->next;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000336 } else if (cc->type == CNT_DEL) {
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000337 old++; /* Don't use this old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000338 } else {
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000339 if (cc->type == CNT_CHANGE) {
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000340 if (cc->change % 3 == 1)
341 new->pcnt = old->pcnt + next->cnt_surplus.pcnt;
342 else if (cc->change % 3 == 2)
343 new->pcnt = old->pcnt - next->cnt_surplus.pcnt;
344 else
345 new->pcnt = next->cnt.pcnt;
346 if (cc->change / 3 == 1)
347 new->bcnt = old->bcnt + next->cnt_surplus.bcnt;
348 else if (cc->change / 3 == 2)
349 new->bcnt = old->bcnt - next->cnt_surplus.bcnt;
350 else
351 new->bcnt = next->cnt.bcnt;
Bart De Schuymerab611e22005-02-14 20:20:03 +0000352 } else
353 *new = next->cnt;
354 next->cnt = *new;
355 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000356 if (cc->type == CNT_ADD)
357 new++;
358 else {
359 old++;
360 new++;
361 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000362 next = next->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000363 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000364 cc = cc->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000365 }
366
367 free(u_repl->counters);
368 u_repl->counters = newcounters;
369 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000370 /* Reset the counterchanges to CNT_NORM and delete the unused cc */
371 i = 0;
372 cc = u_repl->cc->next;
373 while (cc != u_repl->cc) {
374 if (cc->type == CNT_DEL) {
375 cc->prev->next = cc->next;
376 cc->next->prev = cc->prev;
377 cc2 = cc->next;
378 free(cc);
379 cc = cc2;
380 } else {
381 cc->type = CNT_NORM;
382 cc->change = 0;
383 i++;
384 cc = cc->next;
385 }
386 }
387 if (i != u_repl->nentries)
388 ebt_print_bug("i != u_repl->nentries");
Bart De Schuymer62423742002-07-14 19:06:20 +0000389 if (u_repl->filename != NULL) {
390 store_counters_in_file(u_repl->filename, u_repl);
391 return;
392 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000393 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
394 sizeof(struct ebt_replace);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000395 /* Now put the stuff in the kernel's struct ebt_replace */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000396 repl.counters = sparc_cast u_repl->counters;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000397 repl.num_counters = u_repl->num_counters;
398 memcpy(repl.name, u_repl->name, sizeof(repl.name));
399
Bart De Schuymer6622a012005-01-19 21:09:05 +0000400 if (get_sockfd())
401 return;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000402 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000403 ebt_print_bug("Couldn't update kernel counters");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000404}
405
406static int
407ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
408{
409 struct ebt_u_match_list *new;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000410 int ret = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000411
412 new = (struct ebt_u_match_list *)
413 malloc(sizeof(struct ebt_u_match_list));
414 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000415 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000416 new->m = (struct ebt_entry_match *)
417 malloc(m->match_size + sizeof(struct ebt_entry_match));
418 if (!new->m)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000419 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000420 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
421 new->next = NULL;
422 **l = new;
423 *l = &new->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000424 if (ebt_find_match(new->m->u.name) == NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000425 ebt_print_error("Kernel match %s unsupported by userspace tool",
426 new->m->u.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000427 ret = -1;
428 }
429 return ret;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000430}
431
432static int
433ebt_translate_watcher(struct ebt_entry_watcher *w,
434 struct ebt_u_watcher_list ***l)
435{
436 struct ebt_u_watcher_list *new;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000437 int ret = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000438
439 new = (struct ebt_u_watcher_list *)
440 malloc(sizeof(struct ebt_u_watcher_list));
441 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000442 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000443 new->w = (struct ebt_entry_watcher *)
444 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
445 if (!new->w)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000446 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000447 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
448 new->next = NULL;
449 **l = new;
450 *l = &new->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000451 if (ebt_find_watcher(new->w->u.name) == NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000452 ebt_print_error("Kernel watcher %s unsupported by userspace "
453 "tool", new->w->u.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000454 ret = -1;
455 }
456 return ret;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000457}
458
459static int
460ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000461 int *totalcnt, struct ebt_u_entry **u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000462 unsigned int valid_hooks, char *base, struct ebt_cntchanges **cc)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000463{
Bart De Schuymer6622a012005-01-19 21:09:05 +0000464 /* An entry */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000465 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
466 struct ebt_u_entry *new;
467 struct ebt_u_match_list **m_l;
468 struct ebt_u_watcher_list **w_l;
469 struct ebt_entry_target *t;
470
471 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
472 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000473 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000474 new->bitmask = e->bitmask;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000475 /*
Bart De Schuymer6622a012005-01-19 21:09:05 +0000476 * Plain userspace code doesn't know about
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000477 * EBT_ENTRY_OR_ENTRIES
478 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000479 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
480 new->invflags = e->invflags;
481 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000482 strcpy(new->in, e->in);
483 strcpy(new->out, e->out);
484 strcpy(new->logical_in, e->logical_in);
485 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000486 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
487 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
488 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
489 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000490 if (*totalcnt >= u_repl->nentries)
491 ebt_print_bug("*totalcnt >= u_repl->nentries");
492 new->cnt = u_repl->counters[*totalcnt];
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000493 new->cnt_surplus.pcnt = new->cnt_surplus.bcnt = 0;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000494 new->cc = *cc;
495 *cc = (*cc)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000496 new->m_list = NULL;
497 new->w_list = NULL;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000498 new->next = (*u_e)->next;
499 new->next->prev = new;
500 (*u_e)->next = new;
501 new->prev = *u_e;
502 *u_e = new;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000503 m_l = &new->m_list;
504 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
505 w_l = &new->w_list;
506 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
507
508 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
509 new->t = (struct ebt_entry_target *)
510 malloc(t->target_size + sizeof(struct ebt_entry_target));
511 if (!new->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000512 ebt_print_memory();
Bart De Schuymer6622a012005-01-19 21:09:05 +0000513 if (ebt_find_target(t->u.name) == NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000514 ebt_print_error("Kernel target %s unsupported by "
515 "userspace tool", t->u.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000516 return -1;
517 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000518 memcpy(new->t, t, t->target_size +
519 sizeof(struct ebt_entry_target));
Bart De Schuymer6622a012005-01-19 21:09:05 +0000520 /* Deal with jumps to udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000521 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
522 char *tmp = base;
523 int verdict = ((struct ebt_standard_target *)t)->verdict;
524 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000525
526 if (verdict >= 0) {
527 tmp += verdict;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000528 for (i = NF_BR_NUMHOOKS; i < u_repl->num_chains; i++)
529 if (u_repl->chains[i]->kernel_start == tmp)
530 break;
531 if (i == u_repl->num_chains)
532 ebt_print_bug("Can't find udc for jump");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000533 ((struct ebt_standard_target *)new->t)->verdict = i;
534 }
535 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000536
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000537 (*cnt)++;
538 (*totalcnt)++;
539 return 0;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000540 } else { /* A new chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000541 int i;
542 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000543
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000544 if (*n != *cnt)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000545 ebt_print_bug("Nr of entries in the chain is wrong");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000546 *n = entries->nentries;
547 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000548 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
549 if (valid_hooks & (1 << i))
550 break;
551 *hook = i;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000552 *u_e = u_repl->chains[*hook]->entries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000553 return 0;
554 }
555}
556
Bart De Schuymer6622a012005-01-19 21:09:05 +0000557/* Initialize all chain headers */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000558static int
559ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
560 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
561{
562 int i;
563 struct ebt_entries *entries = (struct ebt_entries *)e;
564 struct ebt_u_entries *new;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000565
566 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
567 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
568 if (valid_hooks & (1 << i))
569 break;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000570 new = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries));
571 if (!new)
572 ebt_print_memory();
573 if (i == u_repl->max_chains)
574 ebt_double_chains(u_repl);
575 u_repl->chains[i] = new;
576 if (i >= NF_BR_NUMHOOKS)
577 new->kernel_start = (char *)e;
578 *hook = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000579 new->nentries = entries->nentries;
580 new->policy = entries->policy;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000581 new->entries = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
582 if (!new->entries)
583 ebt_print_memory();
584 new->entries->next = new->entries->prev = new->entries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000585 new->counter_offset = entries->counter_offset;
586 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000587 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000588 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000589}
590
Bart De Schuymer6622a012005-01-19 21:09:05 +0000591static int retrieve_from_file(char *filename, struct ebt_replace *repl,
Bart De Schuymer62423742002-07-14 19:06:20 +0000592 char command)
593{
594 FILE *file;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000595 char *hlp = NULL, *entries;
596 struct ebt_counter *counters;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000597 int size, ret = 0;
Bart De Schuymer62423742002-07-14 19:06:20 +0000598
Bart De Schuymer6622a012005-01-19 21:09:05 +0000599 if (!(file = fopen(filename, "r+b"))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000600 ebt_print_error("Could not open file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000601 return -1;
602 }
603 /* Make sure table name is right if command isn't -L or --atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +0000604 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000605 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000606 if (!hlp)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000607 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000608 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000609 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000610 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
Bart De Schuymer6622a012005-01-19 21:09:05 +0000611 != sizeof(struct ebt_replace)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000612 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000613 ret = -1;
614 goto close_file;
615 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000616 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000617 ebt_print_error("File %s contains wrong table name or is "
618 "corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000619 ret = -1;
620 goto close_file;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000621 } else if (!ebt_find_table(repl->name)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000622 ebt_print_error("File %s contains invalid table name",
623 filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000624 ret = -1;
625 goto close_file;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000626 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000627
Bart De Schuymer62423742002-07-14 19:06:20 +0000628 size = sizeof(struct ebt_replace) +
629 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
630 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000631 if (size != ftell(file)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000632 ebt_print_error("File %s has wrong size", filename);
Bart De Schuymer2f7e8d12005-01-19 21:23:02 +0000633 ret = -1;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000634 goto close_file;
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000635 }
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000636 entries = (char *)malloc(repl->entries_size);
637 if (!entries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000638 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000639 repl->entries = sparc_cast entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000640 if (repl->nentries) {
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000641 counters = (struct ebt_counter *)
Bart De Schuymer62423742002-07-14 19:06:20 +0000642 malloc(repl->nentries * sizeof(struct ebt_counter));
Bart De Schuymer8e96bee2003-08-27 16:59:39 +0000643 repl->counters = sparc_cast counters;
Bart De Schuymer62423742002-07-14 19:06:20 +0000644 if (!repl->counters)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000645 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000646 } else
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000647 repl->counters = sparc_cast NULL;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000648 /* Copy entries and counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000649 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000650 fread((char *)repl->entries, sizeof(char), repl->entries_size, file)
Bart De Schuymer62423742002-07-14 19:06:20 +0000651 != repl->entries_size ||
Bart De Schuymer64182a32004-01-21 20:39:54 +0000652 fseek(file, sizeof(struct ebt_replace) + repl->entries_size,
653 SEEK_SET)
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000654 || fread((char *)repl->counters, sizeof(char),
Bart De Schuymer62423742002-07-14 19:06:20 +0000655 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000656 != repl->nentries * sizeof(struct ebt_counter)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000657 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000658 free(entries);
659 repl->entries = NULL;
660 ret = -1;
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000661 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000662close_file:
Bart De Schuymer62423742002-07-14 19:06:20 +0000663 fclose(file);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000664 free(hlp);
665 return ret;
Bart De Schuymer62423742002-07-14 19:06:20 +0000666}
667
Bart De Schuymer64182a32004-01-21 20:39:54 +0000668static int retrieve_from_kernel(struct ebt_replace *repl, char command,
669 int init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000670{
671 socklen_t optlen;
672 int optname;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000673 char *entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000674
675 optlen = sizeof(struct ebt_replace);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000676 if (get_sockfd())
677 return -1;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000678 /* --atomic-init || --init-table */
Bart De Schuymer64182a32004-01-21 20:39:54 +0000679 if (init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000680 optname = EBT_SO_GET_INIT_INFO;
681 else
682 optname = EBT_SO_GET_INFO;
683 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
684 return -1;
685
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000686 if ( !(entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer64182a32004-01-21 20:39:54 +0000687 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000688 repl->entries = sparc_cast entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000689 if (repl->nentries) {
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000690 struct ebt_counter *counters;
691
692 if (!(counters = (struct ebt_counter *)
Bart De Schuymer62423742002-07-14 19:06:20 +0000693 malloc(repl->nentries * sizeof(struct ebt_counter))) )
Bart De Schuymer64182a32004-01-21 20:39:54 +0000694 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000695 repl->counters = sparc_cast counters;
Bart De Schuymer62423742002-07-14 19:06:20 +0000696 }
697 else
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000698 repl->counters = sparc_cast NULL;
Bart De Schuymer62423742002-07-14 19:06:20 +0000699
Bart De Schuymer6622a012005-01-19 21:09:05 +0000700 /* We want to receive the counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000701 repl->num_counters = repl->nentries;
702 optlen += repl->entries_size + repl->num_counters *
703 sizeof(struct ebt_counter);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000704 if (init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000705 optname = EBT_SO_GET_INIT_ENTRIES;
706 else
707 optname = EBT_SO_GET_ENTRIES;
708 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
Bart De Schuymer6622a012005-01-19 21:09:05 +0000709 ebt_print_bug("Hmm, what is wrong??? bug#1");
Bart De Schuymer62423742002-07-14 19:06:20 +0000710
711 return 0;
712}
713
Bart De Schuymer64182a32004-01-21 20:39:54 +0000714int ebt_get_table(struct ebt_u_replace *u_repl, int init)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000715{
716 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000717 struct ebt_replace repl;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000718 struct ebt_u_entry *u_e;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000719 struct ebt_cntchanges *new_cc, *cc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000720
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000721 strcpy(repl.name, u_repl->name);
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000722 if (u_repl->filename != NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000723 if (init)
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000724 ebt_print_bug("Getting initial table data from a file is impossible");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000725 if (retrieve_from_file(u_repl->filename, &repl, u_repl->command))
726 return -1;
727 /* -L with a wrong table name should be dealt with silently */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000728 strcpy(u_repl->name, repl.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000729 } else if (retrieve_from_kernel(&repl, u_repl->command, init))
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000730 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000731
Bart De Schuymer6622a012005-01-19 21:09:05 +0000732 /* Translate the struct ebt_replace to a struct ebt_u_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000733 u_repl->valid_hooks = repl.valid_hooks;
734 u_repl->nentries = repl.nentries;
735 u_repl->num_counters = repl.num_counters;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000736 u_repl->counters = repl.counters;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000737 u_repl->cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
738 if (!u_repl->cc)
739 ebt_print_memory();
740 u_repl->cc->next = u_repl->cc->prev = u_repl->cc;
741 cc = u_repl->cc;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000742 for (i = 0; i < repl.nentries; i++) {
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000743 new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000744 if (!new_cc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000745 ebt_print_memory();
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000746 new_cc->type = CNT_NORM;
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000747 new_cc->change = 0;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000748 new_cc->prev = cc;
749 cc->next = new_cc;
750 cc = new_cc;
751 }
752 if (repl.nentries) {
753 new_cc->next = u_repl->cc;
754 u_repl->cc->prev = new_cc;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000755 }
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000756 u_repl->chains = (struct ebt_u_entries **)calloc(EBT_ORI_MAX_CHAINS, sizeof(void *));
757 u_repl->max_chains = EBT_ORI_MAX_CHAINS;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000758 hook = -1;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000759 /* FIXME: Clean up when an error is encountered */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000760 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
761 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000762 if (hook >= NF_BR_NUMHOOKS)
763 u_repl->num_chains = hook + 1;
764 else
765 u_repl->num_chains = NF_BR_NUMHOOKS;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000766 i = 0; /* Holds the expected nr. of entries for the chain */
767 j = 0; /* Holds the up to now counted entries for the chain */
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000768 k = 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000769 cc = u_repl->cc->next;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000770 hook = -1;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000771 EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size,
772 ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl,
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000773 u_repl->valid_hooks, (char *)repl.entries, &cc);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000774 if (k != u_repl->nentries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000775 ebt_print_bug("Wrong total nentries");
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000776 free(repl.entries);
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000777 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000778}