blob: 4b89a65dacc79211e2bd5937d2fbbc04af83aed1 [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.
Bart De Schuymer6bdb9f42005-11-09 22:39:03 +000012 * The other code works with linked lists. So, the translation is done here.
Bart De Schuymer9895a8e2003-01-11 10:14:24 +000013 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000014
15#include <getopt.h>
16#include <string.h>
17#include <errno.h>
18#include <stdio.h>
19#include <stdlib.h>
Bart De Schuymer6bdb9f42005-11-09 22:39:03 +000020#include <fcntl.h>
21#include <unistd.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000022#include <sys/socket.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000023#include "include/ebtables_u.h"
24
25extern char* hooknames[NF_BR_NUMHOOKS];
26
Bart De Schuymerf81c2702003-07-23 21:07:04 +000027#ifdef KERNEL_64_USERSPACE_32
28#define sparc_cast (uint64_t)
29#else
30#define sparc_cast
31#endif
32
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000033int sockfd = -1;
34
Bart De Schuymer6622a012005-01-19 21:09:05 +000035static int get_sockfd()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000036{
Bart De Schuymer6622a012005-01-19 21:09:05 +000037 int ret = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000038 if (sockfd == -1) {
39 sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
Bart De Schuymer6622a012005-01-19 21:09:05 +000040 if (sockfd < 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +000041 ebt_print_error("Problem getting a socket, "
42 "you probably don't have the right "
43 "permissions");
Bart De Schuymer6622a012005-01-19 21:09:05 +000044 ret = -1;
45 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000046 }
Bart De Schuymer6622a012005-01-19 21:09:05 +000047 return ret;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000048}
49
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +000050static struct ebt_replace *translate_user2kernel(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000051{
52 struct ebt_replace *new;
53 struct ebt_u_entry *e;
54 struct ebt_u_match_list *m_l;
55 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +000056 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000057 char *p, *base;
58 int i, j;
Bart De Schuymer60332e02002-06-23 08:01:47 +000059 unsigned int entries_size = 0, *chain_offsets;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000060
61 new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
62 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +000063 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000064 new->valid_hooks = u_repl->valid_hooks;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +000065 strcpy(new->name, u_repl->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000066 new->nentries = u_repl->nentries;
67 new->num_counters = u_repl->num_counters;
Bart De Schuymerf81c2702003-07-23 21:07:04 +000068 new->counters = sparc_cast u_repl->counters;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +000069 chain_offsets = (unsigned int *)malloc(u_repl->num_chains * sizeof(unsigned int));
Bart De Schuymer6622a012005-01-19 21:09:05 +000070 /* Determine size */
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +000071 for (i = 0; i < u_repl->num_chains; i++) {
72 if (!(entries = u_repl->chains[i]))
73 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +000074 chain_offsets[i] = entries_size;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000075 entries_size += sizeof(struct ebt_entries);
76 j = 0;
Bart De Schuymere94eaf72005-08-28 16:06:22 +000077 e = entries->entries->next;
78 while (e != entries->entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000079 j++;
80 entries_size += sizeof(struct ebt_entry);
81 m_l = e->m_list;
82 while (m_l) {
83 entries_size += m_l->m->match_size +
84 sizeof(struct ebt_entry_match);
85 m_l = m_l->next;
86 }
87 w_l = e->w_list;
88 while (w_l) {
89 entries_size += w_l->w->watcher_size +
90 sizeof(struct ebt_entry_watcher);
91 w_l = w_l->next;
92 }
93 entries_size += e->t->target_size +
94 sizeof(struct ebt_entry_target);
95 e = e->next;
96 }
Bart De Schuymer6622a012005-01-19 21:09:05 +000097 /* A little sanity check */
Bart De Schuymer60332e02002-06-23 08:01:47 +000098 if (j != entries->nentries)
Bart De Schuymer64182a32004-01-21 20:39:54 +000099 ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000100 entries->nentries, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000101 }
102
103 new->entries_size = entries_size;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000104 p = (char *)malloc(entries_size);
105 if (!p)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000106 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000107
Bart De Schuymer6622a012005-01-19 21:09:05 +0000108 /* Put everything in one block */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000109 new->entries = sparc_cast p;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000110 for (i = 0; i < u_repl->num_chains; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000111 struct ebt_entries *hlp;
112
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000113 hlp = (struct ebt_entries *)p;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000114 if (!(entries = u_repl->chains[i]))
115 continue;
116 if (i < NF_BR_NUMHOOKS)
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000117 new->hook_entry[i] = sparc_cast hlp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000118 hlp->nentries = entries->nentries;
119 hlp->policy = entries->policy;
120 strcpy(hlp->name, entries->name);
121 hlp->counter_offset = entries->counter_offset;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000122 hlp->distinguisher = 0; /* Make the kernel see the light */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000123 p += sizeof(struct ebt_entries);
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000124 e = entries->entries->next;
125 while (e != entries->entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000126 struct ebt_entry *tmp = (struct ebt_entry *)p;
127
128 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
129 tmp->invflags = e->invflags;
130 tmp->ethproto = e->ethproto;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000131 strcpy(tmp->in, e->in);
132 strcpy(tmp->out, e->out);
133 strcpy(tmp->logical_in, e->logical_in);
134 strcpy(tmp->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000135 memcpy(tmp->sourcemac, e->sourcemac,
136 sizeof(tmp->sourcemac));
137 memcpy(tmp->sourcemsk, e->sourcemsk,
138 sizeof(tmp->sourcemsk));
139 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
140 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
141
142 base = p;
143 p += sizeof(struct ebt_entry);
144 m_l = e->m_list;
145 while (m_l) {
146 memcpy(p, m_l->m, m_l->m->match_size +
147 sizeof(struct ebt_entry_match));
148 p += m_l->m->match_size +
149 sizeof(struct ebt_entry_match);
150 m_l = m_l->next;
151 }
152 tmp->watchers_offset = p - base;
153 w_l = e->w_list;
154 while (w_l) {
155 memcpy(p, w_l->w, w_l->w->watcher_size +
156 sizeof(struct ebt_entry_watcher));
157 p += w_l->w->watcher_size +
158 sizeof(struct ebt_entry_watcher);
159 w_l = w_l->next;
160 }
161 tmp->target_offset = p - base;
162 memcpy(p, e->t, e->t->target_size +
163 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000164 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
165 struct ebt_standard_target *st =
166 (struct ebt_standard_target *)p;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000167 /* Translate the jump to a udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000168 if (st->verdict >= 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000169 st->verdict = chain_offsets
170 [st->verdict + NF_BR_NUMHOOKS];
Bart De Schuymer60332e02002-06-23 08:01:47 +0000171 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000172 p += e->t->target_size +
173 sizeof(struct ebt_entry_target);
174 tmp->next_offset = p - base;
175 e = e->next;
176 }
177 }
178
Bart De Schuymer6622a012005-01-19 21:09:05 +0000179 /* Sanity check */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000180 if (p - (char *)new->entries != new->entries_size)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000181 ebt_print_bug("Entries_size bug");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000182 free(chain_offsets);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000183 return new;
184}
185
Bart De Schuymer62423742002-07-14 19:06:20 +0000186static void store_table_in_file(char *filename, struct ebt_replace *repl)
187{
Bart De Schuymer6bdb9f42005-11-09 22:39:03 +0000188 char *data;
Bart De Schuymer62423742002-07-14 19:06:20 +0000189 int size;
Bart De Schuymer6bdb9f42005-11-09 22:39:03 +0000190 int fd;
Bart De Schuymer62423742002-07-14 19:06:20 +0000191
Bart De Schuymer025859c2009-12-11 17:35:01 +0000192 /* Start from an empty file with the correct priviliges */
193 if ((fd = creat(filename, 0600)) == -1) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000194 ebt_print_error("Couldn't create file %s", filename);
Bart De Schuymer6bdb9f42005-11-09 22:39:03 +0000195 return;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000196 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000197
198 size = sizeof(struct ebt_replace) + repl->entries_size +
199 repl->nentries * sizeof(struct ebt_counter);
200 data = (char *)malloc(size);
201 if (!data)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000202 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000203 memcpy(data, repl, sizeof(struct ebt_replace));
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000204 memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries,
Bart De Schuymer62423742002-07-14 19:06:20 +0000205 repl->entries_size);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000206 /* Initialize counters to zero, deliver_counters() can update them */
Bart De Schuymer62423742002-07-14 19:06:20 +0000207 memset(data + sizeof(struct ebt_replace) + repl->entries_size,
208 0, repl->nentries * sizeof(struct ebt_counter));
Bart De Schuymer6bdb9f42005-11-09 22:39:03 +0000209 if (write(fd, data, size) != size)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000210 ebt_print_error("Couldn't write everything to file %s",
211 filename);
Bart De Schuymer6bdb9f42005-11-09 22:39:03 +0000212 close(fd);
Bart De Schuymer62423742002-07-14 19:06:20 +0000213 free(data);
214}
215
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000216void ebt_deliver_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000217{
218 socklen_t optlen;
219 struct ebt_replace *repl;
220
Bart De Schuymer6622a012005-01-19 21:09:05 +0000221 /* Translate the struct ebt_u_replace to a struct ebt_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000222 repl = translate_user2kernel(u_repl);
Bart De Schuymer62423742002-07-14 19:06:20 +0000223 if (u_repl->filename != NULL) {
224 store_table_in_file(u_repl->filename, repl);
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000225 goto free_repl;
Bart De Schuymer62423742002-07-14 19:06:20 +0000226 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000227 /* Give the data to the kernel */
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000228 optlen = sizeof(struct ebt_replace) + repl->entries_size;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000229 if (get_sockfd())
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000230 goto free_repl;
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000231 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000232 goto free_repl;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000233 if (u_repl->command == 8) { /* The ebtables module may not
234 * yet be loaded with --atomic-commit */
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000235 ebtables_insmod("ebtables");
236 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES,
237 repl, optlen))
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000238 goto free_repl;
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000239 }
240
Bart De Schuymer192b91d2011-06-19 19:01:06 +0000241 ebt_print_error("Unable to update the kernel. Two possible causes:\n"
242 "1. Multiple ebtables programs were executing simultaneously. The ebtables\n"
243 " userspace tool doesn't by default support multiple ebtables programs running\n"
244 " concurrently. The ebtables option --concurrent or a tool like flock can be\n"
245 " used to support concurrent scripts that update the ebtables kernel tables.\n"
246 "2. The kernel doesn't support a certain ebtables extension, consider\n"
247 " recompiling your kernel or insmod the extension.\n");
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000248free_repl:
249 if (repl) {
250 free(repl->entries);
251 free(repl);
252 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000253}
254
Bart De Schuymer6622a012005-01-19 21:09:05 +0000255static int store_counters_in_file(char *filename, struct ebt_u_replace *repl)
Bart De Schuymer62423742002-07-14 19:06:20 +0000256{
Bart De Schuymer6622a012005-01-19 21:09:05 +0000257 int size = repl->nentries * sizeof(struct ebt_counter), ret = 0;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000258 unsigned int entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000259 struct ebt_replace hlp;
260 FILE *file;
261
Bart De Schuymer6622a012005-01-19 21:09:05 +0000262 if (!(file = fopen(filename, "r+b"))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000263 ebt_print_error("Could not open file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000264 return -1;
265 }
266 /* Find out entries_size and then set the file pointer to the
267 * counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000268 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
269 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
270 sizeof(unsigned int) ||
271 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000272 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000273 ret = -1;
274 goto close_file;
Bart De Schuymer62423742002-07-14 19:06:20 +0000275 }
276 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000277 ebt_print_error("Could not write everything to file %s",
278 filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000279 ret = -1;
Bart De Schuymer62423742002-07-14 19:06:20 +0000280 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000281close_file:
Bart De Schuymer62423742002-07-14 19:06:20 +0000282 fclose(file);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000283 return 0;
Bart De Schuymer62423742002-07-14 19:06:20 +0000284}
285
Bart De Schuymer6622a012005-01-19 21:09:05 +0000286/* Gets executed after ebt_deliver_table. Delivers the counters to the kernel
287 * and resets the counterchanges to CNT_NORM */
Bart De Schuymer83a1b0f2005-09-28 19:36:17 +0000288void ebt_deliver_counters(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000289{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000290 struct ebt_counter *old, *new, *newcounters;
291 socklen_t optlen;
292 struct ebt_replace repl;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000293 struct ebt_cntchanges *cc = u_repl->cc->next, *cc2;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000294 struct ebt_u_entries *entries;
295 struct ebt_u_entry *next = NULL;
296 int i, chainnr = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000297
298 if (u_repl->nentries == 0)
299 return;
300
301 newcounters = (struct ebt_counter *)
302 malloc(u_repl->nentries * sizeof(struct ebt_counter));
303 if (!newcounters)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000304 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000305 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
306 old = u_repl->counters;
307 new = newcounters;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000308 while (cc != u_repl->cc) {
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000309 if (!next || next == entries->entries) {
Bart De Schuymer97783d22009-11-04 21:39:26 +0000310 while (chainnr < u_repl->num_chains && (!(entries = u_repl->chains[chainnr]) ||
311 (next = entries->entries->next) == entries->entries))
312 chainnr++;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000313 if (chainnr == u_repl->num_chains)
314 break;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000315 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000316 if (cc->type == CNT_NORM) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000317 /* 'Normal' rule, meaning we didn't do anything to it
318 * So, we just copy */
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000319 *new = *old;
Bart De Schuymerab611e22005-02-14 20:20:03 +0000320 next->cnt = *new;
321 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000322 old++; /* We've used an old counter */
323 new++; /* We've set a new counter */
Bart De Schuymerff587202005-02-08 20:02:28 +0000324 next = next->next;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000325 } else if (cc->type == CNT_DEL) {
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000326 old++; /* Don't use this old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000327 } else {
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000328 if (cc->type == CNT_CHANGE) {
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000329 if (cc->change % 3 == 1)
330 new->pcnt = old->pcnt + next->cnt_surplus.pcnt;
331 else if (cc->change % 3 == 2)
332 new->pcnt = old->pcnt - next->cnt_surplus.pcnt;
333 else
334 new->pcnt = next->cnt.pcnt;
335 if (cc->change / 3 == 1)
336 new->bcnt = old->bcnt + next->cnt_surplus.bcnt;
337 else if (cc->change / 3 == 2)
338 new->bcnt = old->bcnt - next->cnt_surplus.bcnt;
339 else
340 new->bcnt = next->cnt.bcnt;
Bart De Schuymerab611e22005-02-14 20:20:03 +0000341 } else
342 *new = next->cnt;
343 next->cnt = *new;
344 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000345 if (cc->type == CNT_ADD)
346 new++;
347 else {
348 old++;
349 new++;
350 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000351 next = next->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000352 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000353 cc = cc->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000354 }
355
356 free(u_repl->counters);
357 u_repl->counters = newcounters;
358 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000359 /* Reset the counterchanges to CNT_NORM and delete the unused cc */
360 i = 0;
361 cc = u_repl->cc->next;
362 while (cc != u_repl->cc) {
363 if (cc->type == CNT_DEL) {
364 cc->prev->next = cc->next;
365 cc->next->prev = cc->prev;
366 cc2 = cc->next;
367 free(cc);
368 cc = cc2;
369 } else {
370 cc->type = CNT_NORM;
371 cc->change = 0;
372 i++;
373 cc = cc->next;
374 }
375 }
376 if (i != u_repl->nentries)
377 ebt_print_bug("i != u_repl->nentries");
Bart De Schuymer62423742002-07-14 19:06:20 +0000378 if (u_repl->filename != NULL) {
379 store_counters_in_file(u_repl->filename, u_repl);
380 return;
381 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000382 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
383 sizeof(struct ebt_replace);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000384 /* Now put the stuff in the kernel's struct ebt_replace */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000385 repl.counters = sparc_cast u_repl->counters;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000386 repl.num_counters = u_repl->num_counters;
387 memcpy(repl.name, u_repl->name, sizeof(repl.name));
388
Bart De Schuymer6622a012005-01-19 21:09:05 +0000389 if (get_sockfd())
390 return;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000391 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000392 ebt_print_bug("Couldn't update kernel counters");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000393}
394
395static int
396ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
397{
398 struct ebt_u_match_list *new;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000399 int ret = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000400
401 new = (struct ebt_u_match_list *)
402 malloc(sizeof(struct ebt_u_match_list));
403 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000404 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000405 new->m = (struct ebt_entry_match *)
406 malloc(m->match_size + sizeof(struct ebt_entry_match));
407 if (!new->m)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000408 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000409 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
410 new->next = NULL;
411 **l = new;
412 *l = &new->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000413 if (ebt_find_match(new->m->u.name) == NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000414 ebt_print_error("Kernel match %s unsupported by userspace tool",
415 new->m->u.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000416 ret = -1;
417 }
418 return ret;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000419}
420
421static int
422ebt_translate_watcher(struct ebt_entry_watcher *w,
423 struct ebt_u_watcher_list ***l)
424{
425 struct ebt_u_watcher_list *new;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000426 int ret = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000427
428 new = (struct ebt_u_watcher_list *)
429 malloc(sizeof(struct ebt_u_watcher_list));
430 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000431 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000432 new->w = (struct ebt_entry_watcher *)
433 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
434 if (!new->w)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000435 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000436 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
437 new->next = NULL;
438 **l = new;
439 *l = &new->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000440 if (ebt_find_watcher(new->w->u.name) == NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000441 ebt_print_error("Kernel watcher %s unsupported by userspace "
442 "tool", new->w->u.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000443 ret = -1;
444 }
445 return ret;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000446}
447
448static int
Bart De Schuymer510c9ce2006-01-23 18:50:54 +0000449ebt_translate_entry(struct ebt_entry *e, int *hook, int *n, int *cnt,
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000450 int *totalcnt, struct ebt_u_entry **u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000451 unsigned int valid_hooks, char *base, struct ebt_cntchanges **cc)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000452{
Bart De Schuymer6622a012005-01-19 21:09:05 +0000453 /* An entry */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000454 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
455 struct ebt_u_entry *new;
456 struct ebt_u_match_list **m_l;
457 struct ebt_u_watcher_list **w_l;
458 struct ebt_entry_target *t;
459
460 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
461 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000462 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000463 new->bitmask = e->bitmask;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000464 /*
Bart De Schuymer6622a012005-01-19 21:09:05 +0000465 * Plain userspace code doesn't know about
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000466 * EBT_ENTRY_OR_ENTRIES
467 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000468 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
469 new->invflags = e->invflags;
470 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000471 strcpy(new->in, e->in);
472 strcpy(new->out, e->out);
473 strcpy(new->logical_in, e->logical_in);
474 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000475 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
476 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
477 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
478 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000479 if (*totalcnt >= u_repl->nentries)
480 ebt_print_bug("*totalcnt >= u_repl->nentries");
481 new->cnt = u_repl->counters[*totalcnt];
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000482 new->cnt_surplus.pcnt = new->cnt_surplus.bcnt = 0;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000483 new->cc = *cc;
484 *cc = (*cc)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000485 new->m_list = NULL;
486 new->w_list = NULL;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000487 new->next = (*u_e)->next;
488 new->next->prev = new;
489 (*u_e)->next = new;
490 new->prev = *u_e;
491 *u_e = new;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000492 m_l = &new->m_list;
493 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
494 w_l = &new->w_list;
495 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
496
497 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
498 new->t = (struct ebt_entry_target *)
499 malloc(t->target_size + sizeof(struct ebt_entry_target));
500 if (!new->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000501 ebt_print_memory();
Bart De Schuymer6622a012005-01-19 21:09:05 +0000502 if (ebt_find_target(t->u.name) == NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000503 ebt_print_error("Kernel target %s unsupported by "
504 "userspace tool", t->u.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000505 return -1;
506 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000507 memcpy(new->t, t, t->target_size +
508 sizeof(struct ebt_entry_target));
Bart De Schuymer6622a012005-01-19 21:09:05 +0000509 /* Deal with jumps to udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000510 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
511 char *tmp = base;
512 int verdict = ((struct ebt_standard_target *)t)->verdict;
513 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000514
515 if (verdict >= 0) {
516 tmp += verdict;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000517 for (i = NF_BR_NUMHOOKS; i < u_repl->num_chains; i++)
518 if (u_repl->chains[i]->kernel_start == tmp)
519 break;
520 if (i == u_repl->num_chains)
521 ebt_print_bug("Can't find udc for jump");
Bart De Schuymer201e1b72006-03-13 19:31:13 +0000522 ((struct ebt_standard_target *)new->t)->verdict = i-NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000523 }
524 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000525
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000526 (*cnt)++;
527 (*totalcnt)++;
528 return 0;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000529 } else { /* A new chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000530 int i;
531 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000532
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000533 if (*n != *cnt)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000534 ebt_print_bug("Nr of entries in the chain is wrong");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000535 *n = entries->nentries;
536 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000537 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
538 if (valid_hooks & (1 << i))
539 break;
540 *hook = i;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000541 *u_e = u_repl->chains[*hook]->entries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000542 return 0;
543 }
544}
545
Bart De Schuymer6622a012005-01-19 21:09:05 +0000546/* Initialize all chain headers */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000547static int
Bart De Schuymer510c9ce2006-01-23 18:50:54 +0000548ebt_translate_chains(struct ebt_entry *e, int *hook,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000549 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
550{
551 int i;
552 struct ebt_entries *entries = (struct ebt_entries *)e;
553 struct ebt_u_entries *new;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000554
555 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
556 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
557 if (valid_hooks & (1 << i))
558 break;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000559 new = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries));
560 if (!new)
561 ebt_print_memory();
562 if (i == u_repl->max_chains)
563 ebt_double_chains(u_repl);
564 u_repl->chains[i] = new;
565 if (i >= NF_BR_NUMHOOKS)
566 new->kernel_start = (char *)e;
567 *hook = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000568 new->nentries = entries->nentries;
569 new->policy = entries->policy;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000570 new->entries = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
571 if (!new->entries)
572 ebt_print_memory();
573 new->entries->next = new->entries->prev = new->entries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000574 new->counter_offset = entries->counter_offset;
575 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000576 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000577 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000578}
579
Bart De Schuymer6622a012005-01-19 21:09:05 +0000580static int retrieve_from_file(char *filename, struct ebt_replace *repl,
Bart De Schuymer62423742002-07-14 19:06:20 +0000581 char command)
582{
583 FILE *file;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000584 char *hlp = NULL, *entries;
585 struct ebt_counter *counters;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000586 int size, ret = 0;
Bart De Schuymer62423742002-07-14 19:06:20 +0000587
Bart De Schuymer6622a012005-01-19 21:09:05 +0000588 if (!(file = fopen(filename, "r+b"))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000589 ebt_print_error("Could not open file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000590 return -1;
591 }
592 /* Make sure table name is right if command isn't -L or --atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +0000593 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000594 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000595 if (!hlp)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000596 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000597 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000598 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000599 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
Bart De Schuymer6622a012005-01-19 21:09:05 +0000600 != sizeof(struct ebt_replace)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000601 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000602 ret = -1;
603 goto close_file;
604 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000605 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000606 ebt_print_error("File %s contains wrong table name or is "
607 "corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000608 ret = -1;
609 goto close_file;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000610 } else if (!ebt_find_table(repl->name)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000611 ebt_print_error("File %s contains invalid table name",
612 filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000613 ret = -1;
614 goto close_file;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000615 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000616
Bart De Schuymer62423742002-07-14 19:06:20 +0000617 size = sizeof(struct ebt_replace) +
618 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
619 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000620 if (size != ftell(file)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000621 ebt_print_error("File %s has wrong size", filename);
Bart De Schuymer2f7e8d12005-01-19 21:23:02 +0000622 ret = -1;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000623 goto close_file;
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000624 }
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000625 entries = (char *)malloc(repl->entries_size);
626 if (!entries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000627 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000628 repl->entries = sparc_cast entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000629 if (repl->nentries) {
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000630 counters = (struct ebt_counter *)
Bart De Schuymer62423742002-07-14 19:06:20 +0000631 malloc(repl->nentries * sizeof(struct ebt_counter));
Bart De Schuymer8e96bee2003-08-27 16:59:39 +0000632 repl->counters = sparc_cast counters;
Bart De Schuymer62423742002-07-14 19:06:20 +0000633 if (!repl->counters)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000634 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000635 } else
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000636 repl->counters = sparc_cast NULL;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000637 /* Copy entries and counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000638 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000639 fread((char *)repl->entries, sizeof(char), repl->entries_size, file)
Bart De Schuymer62423742002-07-14 19:06:20 +0000640 != repl->entries_size ||
Bart De Schuymer64182a32004-01-21 20:39:54 +0000641 fseek(file, sizeof(struct ebt_replace) + repl->entries_size,
642 SEEK_SET)
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000643 || fread((char *)repl->counters, sizeof(char),
Bart De Schuymer62423742002-07-14 19:06:20 +0000644 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000645 != repl->nentries * sizeof(struct ebt_counter)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000646 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000647 free(entries);
648 repl->entries = NULL;
649 ret = -1;
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000650 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000651close_file:
Bart De Schuymer62423742002-07-14 19:06:20 +0000652 fclose(file);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000653 free(hlp);
654 return ret;
Bart De Schuymer62423742002-07-14 19:06:20 +0000655}
656
Bart De Schuymer64182a32004-01-21 20:39:54 +0000657static int retrieve_from_kernel(struct ebt_replace *repl, char command,
658 int init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000659{
660 socklen_t optlen;
661 int optname;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000662 char *entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000663
664 optlen = sizeof(struct ebt_replace);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000665 if (get_sockfd())
666 return -1;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000667 /* --atomic-init || --init-table */
Bart De Schuymer64182a32004-01-21 20:39:54 +0000668 if (init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000669 optname = EBT_SO_GET_INIT_INFO;
670 else
671 optname = EBT_SO_GET_INFO;
672 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
673 return -1;
674
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000675 if ( !(entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer64182a32004-01-21 20:39:54 +0000676 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000677 repl->entries = sparc_cast entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000678 if (repl->nentries) {
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000679 struct ebt_counter *counters;
680
681 if (!(counters = (struct ebt_counter *)
Bart De Schuymer62423742002-07-14 19:06:20 +0000682 malloc(repl->nentries * sizeof(struct ebt_counter))) )
Bart De Schuymer64182a32004-01-21 20:39:54 +0000683 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000684 repl->counters = sparc_cast counters;
Bart De Schuymer62423742002-07-14 19:06:20 +0000685 }
686 else
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000687 repl->counters = sparc_cast NULL;
Bart De Schuymer62423742002-07-14 19:06:20 +0000688
Bart De Schuymer6622a012005-01-19 21:09:05 +0000689 /* We want to receive the counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000690 repl->num_counters = repl->nentries;
691 optlen += repl->entries_size + repl->num_counters *
692 sizeof(struct ebt_counter);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000693 if (init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000694 optname = EBT_SO_GET_INIT_ENTRIES;
695 else
696 optname = EBT_SO_GET_ENTRIES;
697 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
Bart De Schuymer6622a012005-01-19 21:09:05 +0000698 ebt_print_bug("Hmm, what is wrong??? bug#1");
Bart De Schuymer62423742002-07-14 19:06:20 +0000699
700 return 0;
701}
702
Bart De Schuymer64182a32004-01-21 20:39:54 +0000703int ebt_get_table(struct ebt_u_replace *u_repl, int init)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000704{
705 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000706 struct ebt_replace repl;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000707 struct ebt_u_entry *u_e;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000708 struct ebt_cntchanges *new_cc, *cc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000709
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000710 strcpy(repl.name, u_repl->name);
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000711 if (u_repl->filename != NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000712 if (init)
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000713 ebt_print_bug("Getting initial table data from a file is impossible");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000714 if (retrieve_from_file(u_repl->filename, &repl, u_repl->command))
715 return -1;
716 /* -L with a wrong table name should be dealt with silently */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000717 strcpy(u_repl->name, repl.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000718 } else if (retrieve_from_kernel(&repl, u_repl->command, init))
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000719 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000720
Bart De Schuymer6622a012005-01-19 21:09:05 +0000721 /* Translate the struct ebt_replace to a struct ebt_u_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000722 u_repl->valid_hooks = repl.valid_hooks;
723 u_repl->nentries = repl.nentries;
724 u_repl->num_counters = repl.num_counters;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000725 u_repl->counters = repl.counters;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000726 u_repl->cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
727 if (!u_repl->cc)
728 ebt_print_memory();
729 u_repl->cc->next = u_repl->cc->prev = u_repl->cc;
730 cc = u_repl->cc;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000731 for (i = 0; i < repl.nentries; i++) {
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000732 new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000733 if (!new_cc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000734 ebt_print_memory();
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000735 new_cc->type = CNT_NORM;
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000736 new_cc->change = 0;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000737 new_cc->prev = cc;
738 cc->next = new_cc;
739 cc = new_cc;
740 }
741 if (repl.nentries) {
742 new_cc->next = u_repl->cc;
743 u_repl->cc->prev = new_cc;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000744 }
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000745 u_repl->chains = (struct ebt_u_entries **)calloc(EBT_ORI_MAX_CHAINS, sizeof(void *));
746 u_repl->max_chains = EBT_ORI_MAX_CHAINS;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000747 hook = -1;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000748 /* FIXME: Clean up when an error is encountered */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000749 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
750 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000751 if (hook >= NF_BR_NUMHOOKS)
752 u_repl->num_chains = hook + 1;
753 else
754 u_repl->num_chains = NF_BR_NUMHOOKS;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000755 i = 0; /* Holds the expected nr. of entries for the chain */
756 j = 0; /* Holds the up to now counted entries for the chain */
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000757 k = 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000758 cc = u_repl->cc->next;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000759 hook = -1;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000760 EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size,
761 ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl,
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000762 u_repl->valid_hooks, (char *)repl.entries, &cc);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000763 if (k != u_repl->nentries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000764 ebt_print_bug("Wrong total nentries");
Bart De Schuymer92579fe2005-09-01 20:35:43 +0000765 free(repl.entries);
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000766 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000767}