1/*
2 * communication.c, v2.0 July 2002
3 *
4 * Author: Bart De Schuymer
5 *
6 */
7
8/*
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. So, the translation is done here.
13 */
14
15#include <getopt.h>
16#include <string.h>
17#include <errno.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <fcntl.h>
21#include <unistd.h>
22#include <sys/socket.h>
23#include "include/ebtables_u.h"
24
25extern char* hooknames[NF_BR_NUMHOOKS];
26
27#ifdef KERNEL_64_USERSPACE_32
28#define sparc_cast (uint64_t)
29#else
30#define sparc_cast
31#endif
32
33int sockfd = -1;
34
35static int get_sockfd()
36{
37	int ret = 0;
38	if (sockfd == -1) {
39		sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
40		if (sockfd < 0) {
41			ebt_print_error("Problem getting a socket, "
42					"you probably don't have the right "
43					"permissions");
44			ret = -1;
45		}
46	}
47	return ret;
48}
49
50static struct ebt_replace *translate_user2kernel(struct ebt_u_replace *u_repl)
51{
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;
56	struct ebt_u_entries *entries;
57	char *p, *base;
58	int i, j;
59	unsigned int entries_size = 0, *chain_offsets;
60
61	new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
62	if (!new)
63		ebt_print_memory();
64	new->valid_hooks = u_repl->valid_hooks;
65	strcpy(new->name, u_repl->name);
66	new->nentries = u_repl->nentries;
67	new->num_counters = u_repl->num_counters;
68	new->counters = sparc_cast u_repl->counters;
69	chain_offsets = (unsigned int *)malloc(u_repl->num_chains * sizeof(unsigned int));
70	/* Determine size */
71	for (i = 0; i < u_repl->num_chains; i++) {
72		if (!(entries = u_repl->chains[i]))
73			continue;
74		chain_offsets[i] = entries_size;
75		entries_size += sizeof(struct ebt_entries);
76		j = 0;
77		e = entries->entries->next;
78		while (e != entries->entries) {
79			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		}
97		/* A little sanity check */
98		if (j != entries->nentries)
99			ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j,
100			   entries->nentries, entries->name);
101	}
102
103	new->entries_size = entries_size;
104	p = (char *)malloc(entries_size);
105	if (!p)
106		ebt_print_memory();
107
108	/* Put everything in one block */
109	new->entries = sparc_cast p;
110	for (i = 0; i < u_repl->num_chains; i++) {
111		struct ebt_entries *hlp;
112
113		hlp = (struct ebt_entries *)p;
114		if (!(entries = u_repl->chains[i]))
115			continue;
116		if (i < NF_BR_NUMHOOKS)
117			new->hook_entry[i] = sparc_cast hlp;
118		hlp->nentries = entries->nentries;
119		hlp->policy = entries->policy;
120		strcpy(hlp->name, entries->name);
121		hlp->counter_offset = entries->counter_offset;
122		hlp->distinguisher = 0; /* Make the kernel see the light */
123		p += sizeof(struct ebt_entries);
124		e = entries->entries->next;
125		while (e != entries->entries) {
126			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;
131			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);
135			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));
164			if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
165				struct ebt_standard_target *st =
166				   (struct ebt_standard_target *)p;
167				/* Translate the jump to a udc */
168				if (st->verdict >= 0)
169					st->verdict = chain_offsets
170					   [st->verdict + NF_BR_NUMHOOKS];
171			}
172			p += e->t->target_size +
173			   sizeof(struct ebt_entry_target);
174			tmp->next_offset = p - base;
175			e = e->next;
176		}
177	}
178
179	/* Sanity check */
180	if (p - (char *)new->entries != new->entries_size)
181		ebt_print_bug("Entries_size bug");
182	free(chain_offsets);
183	return new;
184}
185
186static void store_table_in_file(char *filename, struct ebt_replace *repl)
187{
188	char *data;
189	int size;
190	int fd;
191
192	/* Start from an empty file with the correct priviliges */
193	if ((fd = creat(filename, 0600)) == -1) {
194		ebt_print_error("Couldn't create file %s", filename);
195		return;
196	}
197
198	size = sizeof(struct ebt_replace) + repl->entries_size +
199	   repl->nentries * sizeof(struct ebt_counter);
200	data = (char *)malloc(size);
201	if (!data)
202		ebt_print_memory();
203	memcpy(data, repl, sizeof(struct ebt_replace));
204	memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries,
205	   repl->entries_size);
206	/* Initialize counters to zero, deliver_counters() can update them */
207	memset(data + sizeof(struct ebt_replace) + repl->entries_size,
208	   0, repl->nentries * sizeof(struct ebt_counter));
209	if (write(fd, data, size) != size)
210		ebt_print_error("Couldn't write everything to file %s",
211				filename);
212	close(fd);
213	free(data);
214}
215
216void ebt_deliver_table(struct ebt_u_replace *u_repl)
217{
218	socklen_t optlen;
219	struct ebt_replace *repl;
220
221	/* Translate the struct ebt_u_replace to a struct ebt_replace */
222	repl = translate_user2kernel(u_repl);
223	if (u_repl->filename != NULL) {
224		store_table_in_file(u_repl->filename, repl);
225		goto free_repl;
226	}
227	/* Give the data to the kernel */
228	optlen = sizeof(struct ebt_replace) + repl->entries_size;
229	if (get_sockfd())
230		goto free_repl;
231	if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
232		goto free_repl;
233	if (u_repl->command == 8) { /* The ebtables module may not
234	                             * yet be loaded with --atomic-commit */
235		ebtables_insmod("ebtables");
236		if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES,
237		    repl, optlen))
238			goto free_repl;
239	}
240
241	ebt_print_error("The kernel doesn't support a certain ebtables"
242		    " extension, consider recompiling your kernel or insmod"
243		    " the extension");
244free_repl:
245	if (repl) {
246		free(repl->entries);
247		free(repl);
248	}
249}
250
251static int store_counters_in_file(char *filename, struct ebt_u_replace *repl)
252{
253	int size = repl->nentries * sizeof(struct ebt_counter), ret = 0;
254	unsigned int entries_size;
255	struct ebt_replace hlp;
256	FILE *file;
257
258	if (!(file = fopen(filename, "r+b"))) {
259		ebt_print_error("Could not open file %s", filename);
260		return -1;
261	}
262	/* Find out entries_size and then set the file pointer to the
263	 * counters */
264	if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
265	   || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
266	   sizeof(unsigned int) ||
267	   fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
268		ebt_print_error("File %s is corrupt", filename);
269		ret = -1;
270		goto close_file;
271	}
272	if (fwrite(repl->counters, sizeof(char), size, file) != size) {
273		ebt_print_error("Could not write everything to file %s",
274				filename);
275		ret = -1;
276	}
277close_file:
278	fclose(file);
279	return 0;
280}
281
282/* Gets executed after ebt_deliver_table. Delivers the counters to the kernel
283 * and resets the counterchanges to CNT_NORM */
284void ebt_deliver_counters(struct ebt_u_replace *u_repl)
285{
286	struct ebt_counter *old, *new, *newcounters;
287	socklen_t optlen;
288	struct ebt_replace repl;
289	struct ebt_cntchanges *cc = u_repl->cc->next, *cc2;
290	struct ebt_u_entries *entries;
291	struct ebt_u_entry *next = NULL;
292	int i, chainnr = 0;
293
294	if (u_repl->nentries == 0)
295		return;
296
297	newcounters = (struct ebt_counter *)
298	   malloc(u_repl->nentries * sizeof(struct ebt_counter));
299	if (!newcounters)
300		ebt_print_memory();
301	memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
302	old = u_repl->counters;
303	new = newcounters;
304	while (cc != u_repl->cc) {
305		if (!next || next == entries->entries) {
306			while (chainnr < u_repl->num_chains && (!(entries = u_repl->chains[chainnr]) ||
307			       (next = entries->entries->next) == entries->entries))
308				chainnr++;
309			if (chainnr == u_repl->num_chains)
310				break;
311		}
312		if (cc->type == CNT_NORM) {
313			/* 'Normal' rule, meaning we didn't do anything to it
314			 * So, we just copy */
315			*new = *old;
316			next->cnt = *new;
317			next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
318			old++; /* We've used an old counter */
319			new++; /* We've set a new counter */
320			next = next->next;
321		} else if (cc->type == CNT_DEL) {
322			old++; /* Don't use this old counter */
323		} else {
324			if (cc->type == CNT_CHANGE) {
325				if (cc->change % 3 == 1)
326					new->pcnt = old->pcnt + next->cnt_surplus.pcnt;
327				else if (cc->change % 3 == 2)
328					new->pcnt = old->pcnt - next->cnt_surplus.pcnt;
329				else
330					new->pcnt = next->cnt.pcnt;
331				if (cc->change / 3 == 1)
332					new->bcnt = old->bcnt + next->cnt_surplus.bcnt;
333				else if (cc->change / 3 == 2)
334					new->bcnt = old->bcnt - next->cnt_surplus.bcnt;
335				else
336					new->bcnt = next->cnt.bcnt;
337			} else
338				*new = next->cnt;
339			next->cnt = *new;
340			next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
341			if (cc->type == CNT_ADD)
342				new++;
343			else {
344				old++;
345				new++;
346			}
347			next = next->next;
348		}
349		cc = cc->next;
350	}
351
352	free(u_repl->counters);
353	u_repl->counters = newcounters;
354	u_repl->num_counters = u_repl->nentries;
355	/* Reset the counterchanges to CNT_NORM and delete the unused cc */
356	i = 0;
357	cc = u_repl->cc->next;
358	while (cc != u_repl->cc) {
359		if (cc->type == CNT_DEL) {
360			cc->prev->next = cc->next;
361			cc->next->prev = cc->prev;
362			cc2 = cc->next;
363			free(cc);
364			cc = cc2;
365		} else {
366			cc->type = CNT_NORM;
367			cc->change = 0;
368			i++;
369			cc = cc->next;
370		}
371	}
372	if (i != u_repl->nentries)
373		ebt_print_bug("i != u_repl->nentries");
374	if (u_repl->filename != NULL) {
375		store_counters_in_file(u_repl->filename, u_repl);
376		return;
377	}
378	optlen = u_repl->nentries * sizeof(struct ebt_counter) +
379	   sizeof(struct ebt_replace);
380	/* Now put the stuff in the kernel's struct ebt_replace */
381	repl.counters = sparc_cast u_repl->counters;
382	repl.num_counters = u_repl->num_counters;
383	memcpy(repl.name, u_repl->name, sizeof(repl.name));
384
385	if (get_sockfd())
386		return;
387	if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
388		ebt_print_bug("Couldn't update kernel counters");
389}
390
391static int
392ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
393{
394	struct ebt_u_match_list *new;
395	int ret = 0;
396
397	new = (struct ebt_u_match_list *)
398	   malloc(sizeof(struct ebt_u_match_list));
399	if (!new)
400		ebt_print_memory();
401	new->m = (struct ebt_entry_match *)
402	   malloc(m->match_size + sizeof(struct ebt_entry_match));
403	if (!new->m)
404		ebt_print_memory();
405	memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
406	new->next = NULL;
407	**l = new;
408	*l = &new->next;
409	if (ebt_find_match(new->m->u.name) == NULL) {
410		ebt_print_error("Kernel match %s unsupported by userspace tool",
411				new->m->u.name);
412		ret = -1;
413	}
414	return ret;
415}
416
417static int
418ebt_translate_watcher(struct ebt_entry_watcher *w,
419   struct ebt_u_watcher_list ***l)
420{
421	struct ebt_u_watcher_list *new;
422	int ret = 0;
423
424	new = (struct ebt_u_watcher_list *)
425	   malloc(sizeof(struct ebt_u_watcher_list));
426	if (!new)
427		ebt_print_memory();
428	new->w = (struct ebt_entry_watcher *)
429	   malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
430	if (!new->w)
431		ebt_print_memory();
432	memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
433	new->next = NULL;
434	**l = new;
435	*l = &new->next;
436	if (ebt_find_watcher(new->w->u.name) == NULL) {
437		ebt_print_error("Kernel watcher %s unsupported by userspace "
438				"tool", new->w->u.name);
439		ret = -1;
440	}
441	return ret;
442}
443
444static int
445ebt_translate_entry(struct ebt_entry *e, int *hook, int *n, int *cnt,
446   int *totalcnt, struct ebt_u_entry **u_e, struct ebt_u_replace *u_repl,
447   unsigned int valid_hooks, char *base, struct ebt_cntchanges **cc)
448{
449	/* An entry */
450	if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
451		struct ebt_u_entry *new;
452		struct ebt_u_match_list **m_l;
453		struct ebt_u_watcher_list **w_l;
454		struct ebt_entry_target *t;
455
456		new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
457		if (!new)
458			ebt_print_memory();
459		new->bitmask = e->bitmask;
460		/*
461		 * Plain userspace code doesn't know about
462		 * EBT_ENTRY_OR_ENTRIES
463		 */
464		new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
465		new->invflags = e->invflags;
466		new->ethproto = e->ethproto;
467		strcpy(new->in, e->in);
468		strcpy(new->out, e->out);
469		strcpy(new->logical_in, e->logical_in);
470		strcpy(new->logical_out, e->logical_out);
471		memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
472		memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
473		memcpy(new->destmac, e->destmac, sizeof(new->destmac));
474		memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
475		if (*totalcnt >= u_repl->nentries)
476			ebt_print_bug("*totalcnt >= u_repl->nentries");
477		new->cnt = u_repl->counters[*totalcnt];
478		new->cnt_surplus.pcnt = new->cnt_surplus.bcnt = 0;
479		new->cc = *cc;
480		*cc = (*cc)->next;
481		new->m_list = NULL;
482		new->w_list = NULL;
483		new->next = (*u_e)->next;
484		new->next->prev = new;
485		(*u_e)->next = new;
486		new->prev = *u_e;
487		*u_e = new;
488		m_l = &new->m_list;
489		EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
490		w_l = &new->w_list;
491		EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
492
493		t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
494		new->t = (struct ebt_entry_target *)
495		   malloc(t->target_size + sizeof(struct ebt_entry_target));
496		if (!new->t)
497			ebt_print_memory();
498		if (ebt_find_target(t->u.name) == NULL) {
499			ebt_print_error("Kernel target %s unsupported by "
500					"userspace tool", t->u.name);
501			return -1;
502		}
503		memcpy(new->t, t, t->target_size +
504		   sizeof(struct ebt_entry_target));
505		/* Deal with jumps to udc */
506		if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
507			char *tmp = base;
508			int verdict = ((struct ebt_standard_target *)t)->verdict;
509			int i;
510
511			if (verdict >= 0) {
512				tmp += verdict;
513				for (i = NF_BR_NUMHOOKS; i < u_repl->num_chains; i++)
514					if (u_repl->chains[i]->kernel_start == tmp)
515						break;
516				if (i == u_repl->num_chains)
517					ebt_print_bug("Can't find udc for jump");
518				((struct ebt_standard_target *)new->t)->verdict = i-NF_BR_NUMHOOKS;
519			}
520		}
521
522		(*cnt)++;
523		(*totalcnt)++;
524		return 0;
525	} else { /* A new chain */
526		int i;
527		struct ebt_entries *entries = (struct ebt_entries *)e;
528
529		if (*n != *cnt)
530			ebt_print_bug("Nr of entries in the chain is wrong");
531		*n = entries->nentries;
532		*cnt = 0;
533		for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
534			if (valid_hooks & (1 << i))
535				break;
536		*hook = i;
537		*u_e = u_repl->chains[*hook]->entries;
538		return 0;
539	}
540}
541
542/* Initialize all chain headers */
543static int
544ebt_translate_chains(struct ebt_entry *e, int *hook,
545   struct ebt_u_replace *u_repl, unsigned int valid_hooks)
546{
547	int i;
548	struct ebt_entries *entries = (struct ebt_entries *)e;
549	struct ebt_u_entries *new;
550
551	if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
552		for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
553			if (valid_hooks & (1 << i))
554				break;
555		new = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries));
556		if (!new)
557			ebt_print_memory();
558		if (i == u_repl->max_chains)
559			ebt_double_chains(u_repl);
560		u_repl->chains[i] = new;
561		if (i >= NF_BR_NUMHOOKS)
562			new->kernel_start = (char *)e;
563		*hook = i;
564		new->nentries = entries->nentries;
565		new->policy = entries->policy;
566		new->entries = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
567		if (!new->entries)
568			ebt_print_memory();
569		new->entries->next = new->entries->prev = new->entries;
570		new->counter_offset = entries->counter_offset;
571		strcpy(new->name, entries->name);
572	}
573	return 0;
574}
575
576static int retrieve_from_file(char *filename, struct ebt_replace *repl,
577   char command)
578{
579	FILE *file;
580	char *hlp = NULL, *entries;
581	struct ebt_counter *counters;
582	int size, ret = 0;
583
584	if (!(file = fopen(filename, "r+b"))) {
585		ebt_print_error("Could not open file %s", filename);
586		return -1;
587	}
588	/* Make sure table name is right if command isn't -L or --atomic-commit */
589	if (command != 'L' && command != 8) {
590		hlp = (char *)malloc(strlen(repl->name) + 1);
591		if (!hlp)
592			ebt_print_memory();
593		strcpy(hlp, repl->name);
594	}
595	if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
596	   != sizeof(struct ebt_replace)) {
597		ebt_print_error("File %s is corrupt", filename);
598		ret = -1;
599		goto close_file;
600	}
601	if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
602		ebt_print_error("File %s contains wrong table name or is "
603				"corrupt", filename);
604		ret = -1;
605		goto close_file;
606	} else if (!ebt_find_table(repl->name)) {
607		ebt_print_error("File %s contains invalid table name",
608				filename);
609		ret = -1;
610		goto close_file;
611	}
612
613	size = sizeof(struct ebt_replace) +
614	   repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
615	fseek(file, 0, SEEK_END);
616	if (size != ftell(file)) {
617		ebt_print_error("File %s has wrong size", filename);
618		ret = -1;
619		goto close_file;
620	}
621	entries = (char *)malloc(repl->entries_size);
622	if (!entries)
623		ebt_print_memory();
624	repl->entries = sparc_cast entries;
625	if (repl->nentries) {
626		counters = (struct ebt_counter *)
627		   malloc(repl->nentries * sizeof(struct ebt_counter));
628		repl->counters = sparc_cast counters;
629		if (!repl->counters)
630			ebt_print_memory();
631	} else
632		repl->counters = sparc_cast NULL;
633	/* Copy entries and counters */
634	if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
635	   fread((char *)repl->entries, sizeof(char), repl->entries_size, file)
636	   != repl->entries_size ||
637	   fseek(file, sizeof(struct ebt_replace) + repl->entries_size,
638		 SEEK_SET)
639	   || fread((char *)repl->counters, sizeof(char),
640	   repl->nentries * sizeof(struct ebt_counter), file)
641	   != repl->nentries * sizeof(struct ebt_counter)) {
642		ebt_print_error("File %s is corrupt", filename);
643		free(entries);
644		repl->entries = NULL;
645		ret = -1;
646	}
647close_file:
648	fclose(file);
649	free(hlp);
650	return ret;
651}
652
653static int retrieve_from_kernel(struct ebt_replace *repl, char command,
654				int init)
655{
656	socklen_t optlen;
657	int optname;
658	char *entries;
659
660	optlen = sizeof(struct ebt_replace);
661	if (get_sockfd())
662		return -1;
663	/* --atomic-init || --init-table */
664	if (init)
665		optname = EBT_SO_GET_INIT_INFO;
666	else
667		optname = EBT_SO_GET_INFO;
668	if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
669		return -1;
670
671	if ( !(entries = (char *)malloc(repl->entries_size)) )
672		ebt_print_memory();
673	repl->entries = sparc_cast entries;
674	if (repl->nentries) {
675		struct ebt_counter *counters;
676
677		if (!(counters = (struct ebt_counter *)
678		   malloc(repl->nentries * sizeof(struct ebt_counter))) )
679			ebt_print_memory();
680		repl->counters = sparc_cast counters;
681	}
682	else
683		repl->counters = sparc_cast NULL;
684
685	/* We want to receive the counters */
686	repl->num_counters = repl->nentries;
687	optlen += repl->entries_size + repl->num_counters *
688	   sizeof(struct ebt_counter);
689	if (init)
690		optname = EBT_SO_GET_INIT_ENTRIES;
691	else
692		optname = EBT_SO_GET_ENTRIES;
693	if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
694		ebt_print_bug("Hmm, what is wrong??? bug#1");
695
696	return 0;
697}
698
699int ebt_get_table(struct ebt_u_replace *u_repl, int init)
700{
701	int i, j, k, hook;
702	struct ebt_replace repl;
703	struct ebt_u_entry *u_e;
704	struct ebt_cntchanges *new_cc, *cc;
705
706	strcpy(repl.name, u_repl->name);
707	if (u_repl->filename != NULL) {
708		if (init)
709			ebt_print_bug("Getting initial table data from a file is impossible");
710		if (retrieve_from_file(u_repl->filename, &repl, u_repl->command))
711			return -1;
712		/* -L with a wrong table name should be dealt with silently */
713		strcpy(u_repl->name, repl.name);
714	} else if (retrieve_from_kernel(&repl, u_repl->command, init))
715		return -1;
716
717	/* Translate the struct ebt_replace to a struct ebt_u_replace */
718	u_repl->valid_hooks = repl.valid_hooks;
719	u_repl->nentries = repl.nentries;
720	u_repl->num_counters = repl.num_counters;
721	u_repl->counters = repl.counters;
722	u_repl->cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
723	if (!u_repl->cc)
724		ebt_print_memory();
725	u_repl->cc->next = u_repl->cc->prev = u_repl->cc;
726	cc = u_repl->cc;
727	for (i = 0; i < repl.nentries; i++) {
728		new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
729		if (!new_cc)
730			ebt_print_memory();
731		new_cc->type = CNT_NORM;
732		new_cc->change = 0;
733		new_cc->prev = cc;
734		cc->next = new_cc;
735		cc = new_cc;
736	}
737	if (repl.nentries) {
738		new_cc->next = u_repl->cc;
739		u_repl->cc->prev = new_cc;
740	}
741	u_repl->chains = (struct ebt_u_entries **)calloc(EBT_ORI_MAX_CHAINS, sizeof(void *));
742	u_repl->max_chains = EBT_ORI_MAX_CHAINS;
743	hook = -1;
744	/* FIXME: Clean up when an error is encountered */
745	EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
746	   &hook, u_repl, u_repl->valid_hooks);
747	if (hook >= NF_BR_NUMHOOKS)
748		u_repl->num_chains = hook + 1;
749	else
750		u_repl->num_chains = NF_BR_NUMHOOKS;
751	i = 0; /* Holds the expected nr. of entries for the chain */
752	j = 0; /* Holds the up to now counted entries for the chain */
753	k = 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */
754	cc = u_repl->cc->next;
755	hook = -1;
756	EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size,
757	   ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl,
758	   u_repl->valid_hooks, (char *)repl.entries, &cc);
759	if (k != u_repl->nentries)
760		ebt_print_bug("Wrong total nentries");
761	free(repl.entries);
762	return 0;
763}
764