summaryrefslogtreecommitdiffstats
path: root/userspace/ebtables2/communication.c
diff options
context:
space:
mode:
Diffstat (limited to 'userspace/ebtables2/communication.c')
-rw-r--r--userspace/ebtables2/communication.c183
1 files changed, 164 insertions, 19 deletions
diff --git a/userspace/ebtables2/communication.c b/userspace/ebtables2/communication.c
index 8599d48..3dee991 100644
--- a/userspace/ebtables2/communication.c
+++ b/userspace/ebtables2/communication.c
@@ -27,7 +27,7 @@ extern char* hooknames[NF_BR_NUMHOOKS];
int sockfd = -1;
-void get_sockfd()
+static void get_sockfd()
{
if (sockfd == -1) {
sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
@@ -209,6 +209,47 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
return new;
}
+static void store_table_in_file(char *filename, struct ebt_replace *repl)
+{
+ char *command, *data;
+ int size;
+ FILE *file;
+
+ // start from an empty file with right priviliges
+ command = (char *)malloc(strlen(filename) + 15);
+ if (!command)
+ print_memory();
+ strcpy(command, "cat /dev/null>");
+ strcpy(command + 14, filename);
+ if (system(command))
+ print_error("Couldn't create file %s", filename);
+ strcpy(command, "chmod 600 ");
+ strcpy(command + 10, filename);
+ if (system(command))
+ print_error("Couldn't chmod file %s", filename);
+ free(command);
+
+ size = sizeof(struct ebt_replace) + repl->entries_size +
+ repl->nentries * sizeof(struct ebt_counter);
+ data = (char *)malloc(size);
+ if (!data)
+ print_memory();
+ memcpy(data, repl, sizeof(struct ebt_replace));
+ memcpy(data + sizeof(struct ebt_replace), repl->entries,
+ repl->entries_size);
+ // initialize counters to zero, deliver_counters() can update them
+ memset(data + sizeof(struct ebt_replace) + repl->entries_size,
+ 0, repl->nentries * sizeof(struct ebt_counter));
+ if (!(file = fopen(filename, "wb")))
+ print_error("Could not open file %s", filename);
+ if (fwrite(data, sizeof(char), size, file) != size) {
+ fclose(file);
+ print_error("Could not write everything to file %s", filename);
+ }
+ fclose(file);
+ free(data);
+}
+
void deliver_table(struct ebt_u_replace *u_repl)
{
socklen_t optlen;
@@ -216,15 +257,43 @@ void deliver_table(struct ebt_u_replace *u_repl)
// translate the struct ebt_u_replace to a struct ebt_replace
repl = translate_user2kernel(u_repl);
- get_sockfd();
// give the data to the kernel
optlen = sizeof(struct ebt_replace) + repl->entries_size;
+ if (u_repl->filename != NULL) {
+ store_table_in_file(u_repl->filename, repl);
+ return;
+ }
+ get_sockfd();
if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
print_error("The kernel doesn't support a certain ebtables"
" extension, consider recompiling your kernel or insmod"
" the extension");
}
+static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
+{
+ int size = repl->nentries * sizeof(struct ebt_counter);
+ int entries_size;
+ struct ebt_replace hlp;
+ FILE *file;
+
+ if (!(file = fopen(filename, "r+b")))
+ print_error("Could not open file %s", filename);
+ // find out entries_size and then set the file pointer to the counters
+ if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
+ || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
+ sizeof(unsigned int) ||
+ fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
+ fclose(file);
+ print_error("File %s is corrupt", filename);
+ }
+ if (fwrite(repl->counters, sizeof(char), size, file) != size) {
+ fclose(file);
+ print_error("Could not write everything to file %s", filename);
+ }
+ fclose(file);
+}
+
// gets executed after deliver_table
void
deliver_counters(struct ebt_u_replace *u_repl, unsigned short *counterchanges)
@@ -273,6 +342,10 @@ deliver_counters(struct ebt_u_replace *u_repl, unsigned short *counterchanges)
free(u_repl->counters);
u_repl->counters = newcounters;
u_repl->num_counters = u_repl->nentries;
+ if (u_repl->filename != NULL) {
+ store_counters_in_file(u_repl->filename, u_repl);
+ return;
+ }
optlen = u_repl->nentries * sizeof(struct ebt_counter) +
sizeof(struct ebt_replace);
// now put the stuff in the kernel's struct ebt_replace
@@ -484,38 +557,110 @@ ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
return 0;
}
-// talk with kernel to receive the kernel's table
-int get_table(struct ebt_u_replace *u_repl)
+static void retrieve_from_file(char *filename, struct ebt_replace *repl,
+ char command)
{
- int i, j, k, hook;
- socklen_t optlen;
- struct ebt_replace repl;
- struct ebt_u_entry **u_e;
+ FILE *file;
+ char *hlp;
+ int size;
+
+ if (!(file = fopen(filename, "r+b")))
+ print_error("Could not open file %s", filename);
+ // make sure table name is right if command isn't -L or --atomic-commit
+ if (command != 'L' && command != 8) {
+ hlp = (char *)malloc(strlen(repl->name));
+ if (!hlp)
+ print_memory();
+ strcpy(hlp, repl->name);
+ } else
+ if (!find_table(repl->name))
+ print_error("File %s contains invalid table name",
+ filename);
+ if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
+ != sizeof(struct ebt_replace))
+ print_error("File %s is corrupt", filename);
+ if (command != 'L' && command != 8 && strcmp(hlp, repl->name))
+ print_error("File %s contains wrong table name or is corrupt",
+ filename);
+ size = sizeof(struct ebt_replace) +
+ repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
+ fseek(file, 0, SEEK_END);
+ if (size != ftell(file))
+ print_error("File %s has wrong size", filename);
+ repl->entries = (char *)malloc(repl->entries_size);
+ if (!repl->entries)
+ print_memory();
+ if (repl->nentries) {
+ repl->counters = (struct ebt_counter *)
+ malloc(repl->nentries * sizeof(struct ebt_counter));
+ if (!repl->counters)
+ print_memory();
+ } else
+ repl->counters = NULL;
+ // copy entries and counters
+ if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
+ fread(repl->entries, sizeof(char), repl->entries_size, file)
+ != repl->entries_size ||
+ fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
+ || fread(repl->counters, sizeof(char),
+ repl->nentries * sizeof(struct ebt_counter), file)
+ != repl->nentries * sizeof(struct ebt_counter))
+ print_error("File %s is corrupt", filename);
+ fclose(file);
+}
- get_sockfd();
+static int retrieve_from_kernel(struct ebt_replace *repl, char command)
+{
+ socklen_t optlen;
+ int optname;
optlen = sizeof(struct ebt_replace);
- strcpy(repl.name, u_repl->name);
- if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_INFO, &repl, &optlen))
+ get_sockfd();
+ if (command == 7)
+ optname = EBT_SO_GET_INIT_INFO;
+ else
+ optname = EBT_SO_GET_INFO;
+ if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
return -1;
- if ( !(repl.entries = (char *) malloc(repl.entries_size)) )
+ if ( !(repl->entries = (char *) malloc(repl->entries_size)) )
print_memory();
- if (repl.nentries) {
- if (!(repl.counters = (struct ebt_counter *)
- malloc(repl.nentries * sizeof(struct ebt_counter))) )
+ if (repl->nentries) {
+ if (!(repl->counters = (struct ebt_counter *)
+ malloc(repl->nentries * sizeof(struct ebt_counter))) )
print_memory();
}
else
- repl.counters = NULL;
+ repl->counters = NULL;
// we want to receive the counters
- repl.num_counters = repl.nentries;
- optlen += repl.entries_size + repl.num_counters *
+ repl->num_counters = repl->nentries;
+ optlen += repl->entries_size + repl->num_counters *
sizeof(struct ebt_counter);
- if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_ENTRIES, &repl, &optlen))
+ if (command == 7)
+ optname = EBT_SO_GET_INIT_ENTRIES;
+ else
+ optname = EBT_SO_GET_ENTRIES;
+ if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
print_bug("hmm, what is wrong??? bug#1");
+ return 0;
+}
+
+// talk with kernel to receive the kernel's table
+int get_table(struct ebt_u_replace *u_repl)
+{
+ int i, j, k, hook;
+ struct ebt_replace repl;
+ struct ebt_u_entry **u_e;
+
+ strcpy(repl.name, u_repl->name);
+ if (u_repl->filename != NULL)
+ retrieve_from_file(u_repl->filename, &repl, u_repl->command);
+ else
+ if (retrieve_from_kernel(&repl, u_repl->command) == -1)
+ return -1;
+
// translate the struct ebt_replace to a struct ebt_u_replace
memcpy(u_repl->name, repl.name, sizeof(u_repl->name));
u_repl->valid_hooks = repl.valid_hooks;