blob: bfe9110edf8c0ac38c23243830ea77e1cf5cd4f9 [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
49static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
50{
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_chain_list *cl;
56 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 Schuymer6622a012005-01-19 21:09:05 +000069 /* Determine nr of udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +000070 i = 0;
71 cl = u_repl->udc;
72 while (cl) {
73 i++;
74 cl = cl->next;
75 }
76 i += NF_BR_NUMHOOKS;
77 chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int));
Bart De Schuymer6622a012005-01-19 21:09:05 +000078 /* Determine size */
Bart De Schuymer60332e02002-06-23 08:01:47 +000079 i = 0;
80 cl = u_repl->udc;
81 while (1) {
82 if (i < NF_BR_NUMHOOKS) {
83 if (!(new->valid_hooks & (1 << i))) {
84 i++;
85 continue;
86 }
87 entries = u_repl->hook_entry[i];
88 } else {
89 if (!cl)
90 break;
91 entries = cl->udc;
92 }
93 chain_offsets[i] = entries_size;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000094 entries_size += sizeof(struct ebt_entries);
95 j = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +000096 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000097 while (e) {
98 j++;
99 entries_size += sizeof(struct ebt_entry);
100 m_l = e->m_list;
101 while (m_l) {
102 entries_size += m_l->m->match_size +
103 sizeof(struct ebt_entry_match);
104 m_l = m_l->next;
105 }
106 w_l = e->w_list;
107 while (w_l) {
108 entries_size += w_l->w->watcher_size +
109 sizeof(struct ebt_entry_watcher);
110 w_l = w_l->next;
111 }
112 entries_size += e->t->target_size +
113 sizeof(struct ebt_entry_target);
114 e = e->next;
115 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000116 /* A little sanity check */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000117 if (j != entries->nentries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000118 ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000119 entries->nentries, entries->name);
120 if (i >= NF_BR_NUMHOOKS)
121 cl = cl->next;
122 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000123 }
124
125 new->entries_size = entries_size;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000126 p = (char *)malloc(entries_size);
127 if (!p)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000128 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000129
Bart De Schuymer6622a012005-01-19 21:09:05 +0000130 /* Put everything in one block */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000131 new->entries = sparc_cast p;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000132 i = 0;
133 cl = u_repl->udc;
134 while (1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000135 struct ebt_entries *hlp;
136
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000137 hlp = (struct ebt_entries *)p;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000138 if (i < NF_BR_NUMHOOKS) {
139 if (!(new->valid_hooks & (1 << i))) {
140 i++;
141 continue;
142 }
143 entries = u_repl->hook_entry[i];
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000144 new->hook_entry[i] = sparc_cast hlp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000145 } else {
146 if (!cl)
147 break;
148 entries = cl->udc;
149 }
150 hlp->nentries = entries->nentries;
151 hlp->policy = entries->policy;
152 strcpy(hlp->name, entries->name);
153 hlp->counter_offset = entries->counter_offset;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000154 hlp->distinguisher = 0; /* Make the kernel see the light */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000155 p += sizeof(struct ebt_entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000156 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000157 while (e) {
158 struct ebt_entry *tmp = (struct ebt_entry *)p;
159
160 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
161 tmp->invflags = e->invflags;
162 tmp->ethproto = e->ethproto;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000163 strcpy(tmp->in, e->in);
164 strcpy(tmp->out, e->out);
165 strcpy(tmp->logical_in, e->logical_in);
166 strcpy(tmp->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000167 memcpy(tmp->sourcemac, e->sourcemac,
168 sizeof(tmp->sourcemac));
169 memcpy(tmp->sourcemsk, e->sourcemsk,
170 sizeof(tmp->sourcemsk));
171 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
172 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
173
174 base = p;
175 p += sizeof(struct ebt_entry);
176 m_l = e->m_list;
177 while (m_l) {
178 memcpy(p, m_l->m, m_l->m->match_size +
179 sizeof(struct ebt_entry_match));
180 p += m_l->m->match_size +
181 sizeof(struct ebt_entry_match);
182 m_l = m_l->next;
183 }
184 tmp->watchers_offset = p - base;
185 w_l = e->w_list;
186 while (w_l) {
187 memcpy(p, w_l->w, w_l->w->watcher_size +
188 sizeof(struct ebt_entry_watcher));
189 p += w_l->w->watcher_size +
190 sizeof(struct ebt_entry_watcher);
191 w_l = w_l->next;
192 }
193 tmp->target_offset = p - base;
194 memcpy(p, e->t, e->t->target_size +
195 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000196 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
197 struct ebt_standard_target *st =
198 (struct ebt_standard_target *)p;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000199 /* Translate the jump to a udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000200 if (st->verdict >= 0)
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000201 st->verdict = chain_offsets
202 [st->verdict + NF_BR_NUMHOOKS];
Bart De Schuymer60332e02002-06-23 08:01:47 +0000203 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000204 p += e->t->target_size +
205 sizeof(struct ebt_entry_target);
206 tmp->next_offset = p - base;
207 e = e->next;
208 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000209 if (i >= NF_BR_NUMHOOKS)
210 cl = cl->next;
211 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000212 }
213
Bart De Schuymer6622a012005-01-19 21:09:05 +0000214 /* Sanity check */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000215 if (p - (char *)new->entries != new->entries_size)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000216 ebt_print_bug("Entries_size bug");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000217 free(chain_offsets);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000218 return new;
219}
220
Bart De Schuymer62423742002-07-14 19:06:20 +0000221static void store_table_in_file(char *filename, struct ebt_replace *repl)
222{
223 char *command, *data;
224 int size;
225 FILE *file;
226
Bart De Schuymer6622a012005-01-19 21:09:05 +0000227 /* Start from an empty file with right priviliges */
Bart De Schuymer62423742002-07-14 19:06:20 +0000228 command = (char *)malloc(strlen(filename) + 15);
229 if (!command)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000230 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000231 strcpy(command, "cat /dev/null>");
232 strcpy(command + 14, filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000233 if (system(command)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000234 ebt_print_error("Couldn't create file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000235 goto free_command;
236 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000237 strcpy(command, "chmod 600 ");
238 strcpy(command + 10, filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000239 if (system(command)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000240 ebt_print_error("Couldn't chmod file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000241 goto free_command;
242 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000243
244 size = sizeof(struct ebt_replace) + repl->entries_size +
245 repl->nentries * sizeof(struct ebt_counter);
246 data = (char *)malloc(size);
247 if (!data)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000248 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000249 memcpy(data, repl, sizeof(struct ebt_replace));
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000250 memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries,
Bart De Schuymer62423742002-07-14 19:06:20 +0000251 repl->entries_size);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000252 /* Initialize counters to zero, deliver_counters() can update them */
Bart De Schuymer62423742002-07-14 19:06:20 +0000253 memset(data + sizeof(struct ebt_replace) + repl->entries_size,
254 0, repl->nentries * sizeof(struct ebt_counter));
Bart De Schuymer6622a012005-01-19 21:09:05 +0000255 if (!(file = fopen(filename, "wb"))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000256 ebt_print_error("Couldn't open file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000257 goto free_data;
258 } else if (fwrite(data, sizeof(char), size, file) != size)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000259 ebt_print_error("Couldn't write everything to file %s",
260 filename);
Bart De Schuymer62423742002-07-14 19:06:20 +0000261 fclose(file);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000262free_data:
Bart De Schuymer62423742002-07-14 19:06:20 +0000263 free(data);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000264free_command:
265 free(command);
Bart De Schuymer62423742002-07-14 19:06:20 +0000266}
267
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000268void ebt_deliver_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000269{
270 socklen_t optlen;
271 struct ebt_replace *repl;
272
Bart De Schuymer6622a012005-01-19 21:09:05 +0000273 /* Translate the struct ebt_u_replace to a struct ebt_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000274 repl = translate_user2kernel(u_repl);
Bart De Schuymer62423742002-07-14 19:06:20 +0000275 if (u_repl->filename != NULL) {
276 store_table_in_file(u_repl->filename, repl);
277 return;
278 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000279 /* Give the data to the kernel */
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000280 optlen = sizeof(struct ebt_replace) + repl->entries_size;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000281 if (get_sockfd())
282 return;
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000283 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
284 return;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000285 if (u_repl->command == 8) { /* The ebtables module may not
286 * yet be loaded with --atomic-commit */
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000287 ebtables_insmod("ebtables");
288 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES,
289 repl, optlen))
290 return;
291 }
292
Bart De Schuymer64182a32004-01-21 20:39:54 +0000293 ebt_print_error("The kernel doesn't support a certain ebtables"
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000294 " extension, consider recompiling your kernel or insmod"
295 " the extension");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000296}
297
Bart De Schuymer6622a012005-01-19 21:09:05 +0000298static int store_counters_in_file(char *filename, struct ebt_u_replace *repl)
Bart De Schuymer62423742002-07-14 19:06:20 +0000299{
Bart De Schuymer6622a012005-01-19 21:09:05 +0000300 int size = repl->nentries * sizeof(struct ebt_counter), ret = 0;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000301 unsigned int entries_size;
Bart De Schuymer62423742002-07-14 19:06:20 +0000302 struct ebt_replace hlp;
303 FILE *file;
304
Bart De Schuymer6622a012005-01-19 21:09:05 +0000305 if (!(file = fopen(filename, "r+b"))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000306 ebt_print_error("Could not open file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000307 return -1;
308 }
309 /* Find out entries_size and then set the file pointer to the
310 * counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000311 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
312 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
313 sizeof(unsigned int) ||
314 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000315 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000316 ret = -1;
317 goto close_file;
Bart De Schuymer62423742002-07-14 19:06:20 +0000318 }
319 if (fwrite(repl->counters, sizeof(char), size, file) != size) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000320 ebt_print_error("Could not write everything to file %s",
321 filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000322 ret = -1;
Bart De Schuymer62423742002-07-14 19:06:20 +0000323 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000324close_file:
Bart De Schuymer62423742002-07-14 19:06:20 +0000325 fclose(file);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000326 return 0;
Bart De Schuymer62423742002-07-14 19:06:20 +0000327}
328
Bart De Schuymer6622a012005-01-19 21:09:05 +0000329/* Gets executed after ebt_deliver_table. Delivers the counters to the kernel
330 * and resets the counterchanges to CNT_NORM */
331void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000332{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000333 struct ebt_counter *old, *new, *newcounters;
334 socklen_t optlen;
335 struct ebt_replace repl;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000336 struct ebt_cntchanges *cc = u_repl->counterchanges, *cc2, **cc3;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000337 struct ebt_u_entries *entries;
338 struct ebt_u_entry *next = NULL;
339 int i, chainnr = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000340
341 if (u_repl->nentries == 0)
342 return;
343
344 newcounters = (struct ebt_counter *)
345 malloc(u_repl->nentries * sizeof(struct ebt_counter));
346 if (!newcounters)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000347 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000348 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
349 old = u_repl->counters;
350 new = newcounters;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000351 while (cc) {
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000352 if (!next) {
Bart De Schuymer09a5ea52005-06-18 14:42:44 +0000353 while (!(entries = ebt_nr_to_chain(u_repl, chainnr++)))
354 if (chainnr > NF_BR_NUMHOOKS)
355 goto letscontinue;/* Prevent infinite loop for -D x:-1 */
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000356 if (!(next = entries->entries))
357 continue;
358 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000359 if (cc->type == CNT_NORM) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000360 /* 'Normal' rule, meaning we didn't do anything to it
361 * So, we just copy */
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000362 *new = *old;
Bart De Schuymerab611e22005-02-14 20:20:03 +0000363 next->cnt = *new;
364 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000365 /* We've used an old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000366 old++;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000367 /* We've set a new counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000368 new++;
Bart De Schuymerff587202005-02-08 20:02:28 +0000369 next = next->next;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000370 } else if (cc->type == CNT_DEL) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000371 /* Don't use this old counter */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000372 old++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000373 } else {
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000374 if (cc->type == CNT_CHANGE) {
375 new->pcnt = old->pcnt;
376 if (cc->change % 3 == 1)
377 new->pcnt = old->pcnt + next->cnt_surplus.pcnt;
378 else if (cc->change % 3 == 2)
379 new->pcnt = old->pcnt - next->cnt_surplus.pcnt;
380 else
381 new->pcnt = next->cnt.pcnt;
382 if (cc->change / 3 == 1)
383 new->bcnt = old->bcnt + next->cnt_surplus.bcnt;
384 else if (cc->change / 3 == 2)
385 new->bcnt = old->bcnt - next->cnt_surplus.bcnt;
386 else
387 new->bcnt = next->cnt.bcnt;
Bart De Schuymerab611e22005-02-14 20:20:03 +0000388 } else
389 *new = next->cnt;
390 next->cnt = *new;
391 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000392 if (cc->type == CNT_ADD)
393 new++;
394 else {
395 old++;
396 new++;
397 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000398 next = next->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000399 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000400 cc = cc->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000401 }
Bart De Schuymer09a5ea52005-06-18 14:42:44 +0000402letscontinue:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000403
404 free(u_repl->counters);
405 u_repl->counters = newcounters;
406 u_repl->num_counters = u_repl->nentries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000407 if (u_repl->filename != NULL) {
408 store_counters_in_file(u_repl->filename, u_repl);
409 return;
410 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000411 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
412 sizeof(struct ebt_replace);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000413 /* Now put the stuff in the kernel's struct ebt_replace */
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000414 repl.counters = sparc_cast u_repl->counters;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000415 repl.num_counters = u_repl->num_counters;
416 memcpy(repl.name, u_repl->name, sizeof(repl.name));
417
Bart De Schuymer6622a012005-01-19 21:09:05 +0000418 if (get_sockfd())
419 return;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000420 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000421 ebt_print_bug("Couldn't update kernel counters");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000422
423 if (exec_style != EXEC_STYLE_DAEMON)
424 return;
425 /* Reset the counterchanges to CNT_NORM */
426 cc = u_repl->counterchanges;
427 for (i = 0; i < u_repl->nentries; i++) {
428 cc->type = CNT_NORM;
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000429 cc->change = 0;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000430 cc3 = &cc->next;
431 cc = cc->next;
432 }
433 *cc3 = NULL;
434 while (cc) {
435 cc2 = cc->next;
436 free(cc);
437 cc = cc2;
438 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000439}
440
441static int
442ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
443{
444 struct ebt_u_match_list *new;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000445 int ret = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000446
447 new = (struct ebt_u_match_list *)
448 malloc(sizeof(struct ebt_u_match_list));
449 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000450 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000451 new->m = (struct ebt_entry_match *)
452 malloc(m->match_size + sizeof(struct ebt_entry_match));
453 if (!new->m)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000454 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000455 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
456 new->next = NULL;
457 **l = new;
458 *l = &new->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000459 if (ebt_find_match(new->m->u.name) == NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000460 ebt_print_error("Kernel match %s unsupported by userspace tool",
461 new->m->u.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000462 ret = -1;
463 }
464 return ret;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000465}
466
467static int
468ebt_translate_watcher(struct ebt_entry_watcher *w,
469 struct ebt_u_watcher_list ***l)
470{
471 struct ebt_u_watcher_list *new;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000472 int ret = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000473
474 new = (struct ebt_u_watcher_list *)
475 malloc(sizeof(struct ebt_u_watcher_list));
476 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000477 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000478 new->w = (struct ebt_entry_watcher *)
479 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
480 if (!new->w)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000481 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000482 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
483 new->next = NULL;
484 **l = new;
485 *l = &new->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000486 if (ebt_find_watcher(new->w->u.name) == NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000487 ebt_print_error("Kernel watcher %s unsupported by userspace "
488 "tool", new->w->u.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000489 ret = -1;
490 }
491 return ret;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000492}
493
494static int
495ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
496 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000497 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000498{
Bart De Schuymer6622a012005-01-19 21:09:05 +0000499 /* An entry */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000500 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
501 struct ebt_u_entry *new;
502 struct ebt_u_match_list **m_l;
503 struct ebt_u_watcher_list **w_l;
504 struct ebt_entry_target *t;
505
506 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
507 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000508 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000509 new->bitmask = e->bitmask;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000510 /*
Bart De Schuymer6622a012005-01-19 21:09:05 +0000511 * Plain userspace code doesn't know about
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000512 * EBT_ENTRY_OR_ENTRIES
513 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000514 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
515 new->invflags = e->invflags;
516 new->ethproto = e->ethproto;
Bart De Schuymere3cceb72002-07-26 12:47:33 +0000517 strcpy(new->in, e->in);
518 strcpy(new->out, e->out);
519 strcpy(new->logical_in, e->logical_in);
520 strcpy(new->logical_out, e->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000521 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
522 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
523 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
524 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000525 if (*totalcnt >= u_repl->nentries)
526 ebt_print_bug("*totalcnt >= u_repl->nentries");
527 new->cnt = u_repl->counters[*totalcnt];
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000528 new->cnt_surplus.pcnt = new->cnt_surplus.bcnt = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000529 new->m_list = NULL;
530 new->w_list = NULL;
531 new->next = NULL;
532 m_l = &new->m_list;
533 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
534 w_l = &new->w_list;
535 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
536
537 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
538 new->t = (struct ebt_entry_target *)
539 malloc(t->target_size + sizeof(struct ebt_entry_target));
540 if (!new->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000541 ebt_print_memory();
Bart De Schuymer6622a012005-01-19 21:09:05 +0000542 if (ebt_find_target(t->u.name) == NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000543 ebt_print_error("Kernel target %s unsupported by "
544 "userspace tool", t->u.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000545 return -1;
546 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000547 memcpy(new->t, t, t->target_size +
548 sizeof(struct ebt_entry_target));
Bart De Schuymer6622a012005-01-19 21:09:05 +0000549 /* Deal with jumps to udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000550 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
551 char *tmp = base;
552 int verdict = ((struct ebt_standard_target *)t)->verdict;
553 int i;
554 struct ebt_u_chain_list *cl;
555
556 if (verdict >= 0) {
557 tmp += verdict;
558 cl = u_repl->udc;
559 i = 0;
560 while (cl && cl->kernel_start != tmp) {
561 i++;
562 cl = cl->next;
563 }
564 if (!cl)
Bart De Schuymer6622a012005-01-19 21:09:05 +0000565 ebt_print_bug("Can't find udc for "
Bart De Schuymer64182a32004-01-21 20:39:54 +0000566 "jump");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000567 ((struct ebt_standard_target *)new->t)->verdict = i;
568 }
569 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000570
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000571 /* I love pointers */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000572 **u_e = new;
573 *u_e = &new->next;
574 (*cnt)++;
575 (*totalcnt)++;
576 return 0;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000577 } else { /* A new chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000578 int i;
579 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000580 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000581
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000582 if (*n != *cnt)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000583 ebt_print_bug("Nr of entries in the chain is wrong");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000584 *n = entries->nentries;
585 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000586 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
587 if (valid_hooks & (1 << i))
588 break;
589 *hook = i;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000590 /* Makes use of fact that standard chains come before udc */
591 if (i >= NF_BR_NUMHOOKS) { /* Udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000592 i -= NF_BR_NUMHOOKS;
593 cl = u_repl->udc;
594 while (i-- > 0)
595 cl = cl->next;
596 *u_e = &(cl->udc->entries);
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000597 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000598 *u_e = &(u_repl->hook_entry[*hook]->entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000599 return 0;
600 }
601}
602
Bart De Schuymer6622a012005-01-19 21:09:05 +0000603/* Initialize all chain headers */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000604static int
605ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
606 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
607{
608 int i;
609 struct ebt_entries *entries = (struct ebt_entries *)e;
610 struct ebt_u_entries *new;
611 struct ebt_u_chain_list **chain_list;
612
613 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
614 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
615 if (valid_hooks & (1 << i))
616 break;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000617 /* Makes use of fact that standard chains come before udc */
618 if (i >= NF_BR_NUMHOOKS) { /* Udc */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000619 chain_list = &u_repl->udc;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000620 /* Add in the back */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000621 while (*chain_list)
622 chain_list = &((*chain_list)->next);
623 *chain_list = (struct ebt_u_chain_list *)
624 malloc(sizeof(struct ebt_u_chain_list));
625 if (!(*chain_list))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000626 ebt_print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000627 (*chain_list)->next = NULL;
628 (*chain_list)->udc = (struct ebt_u_entries *)
629 malloc(sizeof(struct ebt_u_entries));
630 if (!((*chain_list)->udc))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000631 ebt_print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000632 new = (*chain_list)->udc;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000633 /* ebt_translate_entry depends on this for knowing
634 * to which chain is being jumped */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000635 (*chain_list)->kernel_start = (char *)e;
636 } else {
637 *hook = i;
638 new = (struct ebt_u_entries *)
639 malloc(sizeof(struct ebt_u_entries));
640 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000641 ebt_print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000642 u_repl->hook_entry[*hook] = new;
643 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000644 new->nentries = entries->nentries;
645 new->policy = entries->policy;
646 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000647 new->counter_offset = entries->counter_offset;
648 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000649 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000650 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000651}
652
Bart De Schuymer6622a012005-01-19 21:09:05 +0000653static int retrieve_from_file(char *filename, struct ebt_replace *repl,
Bart De Schuymer62423742002-07-14 19:06:20 +0000654 char command)
655{
656 FILE *file;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000657 char *hlp = NULL, *entries;
658 struct ebt_counter *counters;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000659 int size, ret = 0;
Bart De Schuymer62423742002-07-14 19:06:20 +0000660
Bart De Schuymer6622a012005-01-19 21:09:05 +0000661 if (!(file = fopen(filename, "r+b"))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000662 ebt_print_error("Could not open file %s", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000663 return -1;
664 }
665 /* Make sure table name is right if command isn't -L or --atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +0000666 if (command != 'L' && command != 8) {
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000667 hlp = (char *)malloc(strlen(repl->name) + 1);
Bart De Schuymer62423742002-07-14 19:06:20 +0000668 if (!hlp)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000669 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000670 strcpy(hlp, repl->name);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000671 }
Bart De Schuymer62423742002-07-14 19:06:20 +0000672 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
Bart De Schuymer6622a012005-01-19 21:09:05 +0000673 != sizeof(struct ebt_replace)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000674 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000675 ret = -1;
676 goto close_file;
677 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000678 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000679 ebt_print_error("File %s contains wrong table name or is "
680 "corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000681 ret = -1;
682 goto close_file;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000683 } else if (!ebt_find_table(repl->name)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000684 ebt_print_error("File %s contains invalid table name",
685 filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000686 ret = -1;
687 goto close_file;
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000688 }
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000689
Bart De Schuymer62423742002-07-14 19:06:20 +0000690 size = sizeof(struct ebt_replace) +
691 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
692 fseek(file, 0, SEEK_END);
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000693 if (size != ftell(file)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000694 ebt_print_error("File %s has wrong size", filename);
Bart De Schuymer2f7e8d12005-01-19 21:23:02 +0000695 ret = -1;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000696 goto close_file;
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000697 }
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000698 entries = (char *)malloc(repl->entries_size);
699 if (!entries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000700 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000701 repl->entries = sparc_cast entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000702 if (repl->nentries) {
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000703 counters = (struct ebt_counter *)
Bart De Schuymer62423742002-07-14 19:06:20 +0000704 malloc(repl->nentries * sizeof(struct ebt_counter));
Bart De Schuymer8e96bee2003-08-27 16:59:39 +0000705 repl->counters = sparc_cast counters;
Bart De Schuymer62423742002-07-14 19:06:20 +0000706 if (!repl->counters)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000707 ebt_print_memory();
Bart De Schuymer62423742002-07-14 19:06:20 +0000708 } else
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000709 repl->counters = sparc_cast NULL;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000710 /* Copy entries and counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000711 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000712 fread((char *)repl->entries, sizeof(char), repl->entries_size, file)
Bart De Schuymer62423742002-07-14 19:06:20 +0000713 != repl->entries_size ||
Bart De Schuymer64182a32004-01-21 20:39:54 +0000714 fseek(file, sizeof(struct ebt_replace) + repl->entries_size,
715 SEEK_SET)
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000716 || fread((char *)repl->counters, sizeof(char),
Bart De Schuymer62423742002-07-14 19:06:20 +0000717 repl->nentries * sizeof(struct ebt_counter), file)
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000718 != repl->nentries * sizeof(struct ebt_counter)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000719 ebt_print_error("File %s is corrupt", filename);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000720 free(entries);
721 repl->entries = NULL;
722 ret = -1;
Bart De Schuymere8890ff2002-07-15 20:29:04 +0000723 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000724close_file:
Bart De Schuymer62423742002-07-14 19:06:20 +0000725 fclose(file);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000726 free(hlp);
727 return ret;
Bart De Schuymer62423742002-07-14 19:06:20 +0000728}
729
Bart De Schuymer64182a32004-01-21 20:39:54 +0000730static int retrieve_from_kernel(struct ebt_replace *repl, char command,
731 int init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000732{
733 socklen_t optlen;
734 int optname;
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000735 char *entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000736
737 optlen = sizeof(struct ebt_replace);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000738 if (get_sockfd())
739 return -1;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000740 /* --atomic-init || --init-table */
Bart De Schuymer64182a32004-01-21 20:39:54 +0000741 if (init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000742 optname = EBT_SO_GET_INIT_INFO;
743 else
744 optname = EBT_SO_GET_INFO;
745 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
746 return -1;
747
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000748 if ( !(entries = (char *)malloc(repl->entries_size)) )
Bart De Schuymer64182a32004-01-21 20:39:54 +0000749 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000750 repl->entries = sparc_cast entries;
Bart De Schuymer62423742002-07-14 19:06:20 +0000751 if (repl->nentries) {
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000752 struct ebt_counter *counters;
753
754 if (!(counters = (struct ebt_counter *)
Bart De Schuymer62423742002-07-14 19:06:20 +0000755 malloc(repl->nentries * sizeof(struct ebt_counter))) )
Bart De Schuymer64182a32004-01-21 20:39:54 +0000756 ebt_print_memory();
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000757 repl->counters = sparc_cast counters;
Bart De Schuymer62423742002-07-14 19:06:20 +0000758 }
759 else
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000760 repl->counters = sparc_cast NULL;
Bart De Schuymer62423742002-07-14 19:06:20 +0000761
Bart De Schuymer6622a012005-01-19 21:09:05 +0000762 /* We want to receive the counters */
Bart De Schuymer62423742002-07-14 19:06:20 +0000763 repl->num_counters = repl->nentries;
764 optlen += repl->entries_size + repl->num_counters *
765 sizeof(struct ebt_counter);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000766 if (init)
Bart De Schuymer62423742002-07-14 19:06:20 +0000767 optname = EBT_SO_GET_INIT_ENTRIES;
768 else
769 optname = EBT_SO_GET_ENTRIES;
770 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
Bart De Schuymer6622a012005-01-19 21:09:05 +0000771 ebt_print_bug("Hmm, what is wrong??? bug#1");
Bart De Schuymer62423742002-07-14 19:06:20 +0000772
773 return 0;
774}
775
Bart De Schuymer64182a32004-01-21 20:39:54 +0000776int ebt_get_table(struct ebt_u_replace *u_repl, int init)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000777{
778 int i, j, k, hook;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000779 struct ebt_replace repl;
780 struct ebt_u_entry **u_e;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000781 struct ebt_cntchanges *new_cc;
782 struct ebt_cntchanges **prev_cc = &(u_repl->counterchanges);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000783
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000784 strcpy(repl.name, u_repl->name);
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000785 if (u_repl->filename != NULL) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000786 if (init)
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000787 ebt_print_bug("Getting initial table data from a file is impossible");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000788 if (retrieve_from_file(u_repl->filename, &repl, u_repl->command))
789 return -1;
790 /* -L with a wrong table name should be dealt with silently */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +0000791 strcpy(u_repl->name, repl.name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000792 } else if (retrieve_from_kernel(&repl, u_repl->command, init))
Bart De Schuymer0cff9e92002-07-25 12:29:50 +0000793 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000794
Bart De Schuymer6622a012005-01-19 21:09:05 +0000795 /* Translate the struct ebt_replace to a struct ebt_u_replace */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000796 u_repl->valid_hooks = repl.valid_hooks;
797 u_repl->nentries = repl.nentries;
798 u_repl->num_counters = repl.num_counters;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000799 u_repl->counters = repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000800 u_repl->udc = NULL;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000801 u_repl->counterchanges = NULL;
802 for (i = 0; i < repl.nentries; i++) {
803 new_cc = (struct ebt_cntchanges *)
804 malloc(sizeof(struct ebt_cntchanges));
805 if (!new_cc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000806 ebt_print_memory();
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000807 new_cc->type = CNT_NORM;
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000808 new_cc->change = 0;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000809 new_cc->next = NULL;
810 *prev_cc = new_cc;
811 prev_cc = &(new_cc->next);
812 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000813 hook = -1;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000814 /* FIXME: Clean up when an error is encountered */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000815 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
816 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000817 i = 0; /* Holds the expected nr. of entries for the chain */
818 j = 0; /* Holds the up to now counted entries for the chain */
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000819 k = 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000820 hook = -1;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000821 EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size,
822 ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl,
823 u_repl->valid_hooks, (char *)repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000824 if (k != u_repl->nentries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000825 ebt_print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000826 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000827}