summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBart De Schuymer <bdschuym@pandora.be>2002-07-14 19:06:20 +0000
committerBart De Schuymer <bdschuym@pandora.be>2002-07-14 19:06:20 +0000
commit624237440835da0dbbba05a97fd9c12a6e84f190 (patch)
tree0d350aa23713dd5542fa0c7db9902492c8481cd7
parent9af14f9b77e97f37068d580ed6a31158912e6598 (diff)
add --atomic options
-rw-r--r--communication.c183
-rw-r--r--ebtables.c72
2 files changed, 222 insertions, 33 deletions
diff --git a/communication.c b/communication.c
index 8599d48..3dee991 100644
--- a/communication.c
+++ b/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;
diff --git a/ebtables.c b/ebtables.c
index b9d20a4..a8e564a 100644
--- a/ebtables.c
+++ b/ebtables.c
@@ -62,7 +62,8 @@ char *hooknames[NF_BR_NUMHOOKS] =
};
// default command line options
-static struct option ebt_original_options[] = {
+static struct option ebt_original_options[] =
+{
{ "append" , required_argument, 0, 'A' },
{ "insert" , required_argument, 0, 'I' },
{ "delete" , required_argument, 0, 'D' },
@@ -94,13 +95,19 @@ static struct option ebt_original_options[] = {
{ "new-chain" , required_argument, 0, 'N' },
{ "rename-chain" , required_argument, 0, 'E' },
{ "delete-chain" , required_argument, 0, 'X' },
+ { "atomic-init" , required_argument, 0, 7 },
+ // communication.c uses fact that atomic-commit equals 8
+ { "atomic-commit" , required_argument, 0, 8 },
+ { "atomic" , required_argument, 0, 9 },
+ { "atomic-save" , required_argument, 0, 10 },
{ 0 }
};
static struct option *ebt_options = ebt_original_options;
// yup, all the possible target names
-char* standard_targets[NUM_STANDARD_TARGETS] = {
+char* standard_targets[NUM_STANDARD_TARGETS] =
+{
"ACCEPT",
"DROP",
"CONTINUE",
@@ -172,7 +179,7 @@ struct ebt_u_table *find_table(char *name)
// Same holds for the struct ebt_match and struct ebt_watcher pointers
struct ebt_u_entry *new_entry;
-void initialize_entry(struct ebt_u_entry *e)
+static void initialize_entry(struct ebt_u_entry *e)
{
e->bitmask = EBT_NOPROTO;
e->invflags = 0;
@@ -191,7 +198,7 @@ void initialize_entry(struct ebt_u_entry *e)
}
// this doesn't free e, becoz the calling function might need e->next
-void free_u_entry(struct ebt_u_entry *e)
+static void free_u_entry(struct ebt_u_entry *e)
{
struct ebt_u_match_list *m_l, *m_l2;
struct ebt_u_watcher_list *w_l, *w_l2;
@@ -406,7 +413,7 @@ int ebtables_insmod(const char *modname, const char *modprobe)
// used to parse /etc/ethertypes
-int disregard_whitespace(char *buffer, FILE *ifp)
+static int disregard_whitespace(char *buffer, FILE *ifp)
{
int hlp;
@@ -419,7 +426,7 @@ int disregard_whitespace(char *buffer, FILE *ifp)
}
// used to parse /etc/ethertypes
-int disregard_tabspace(char *buffer, FILE *ifp)
+static int disregard_tabspace(char *buffer, FILE *ifp)
{
int hlp;
@@ -432,7 +439,7 @@ int disregard_tabspace(char *buffer, FILE *ifp)
}
// helper function: processes a line of data from the file /etc/ethertypes
-int get_a_line(char *buffer, char *value, FILE *ifp)
+static int get_a_line(char *buffer, char *value, FILE *ifp)
{
int i, hlp;
char anotherhlp;
@@ -729,7 +736,7 @@ struct ebt_u_stack
struct ebt_u_entries *entries;
};
-void check_for_loops()
+static void check_for_loops()
{
int chain_nr , i, j , k, sp = 0, verdict;
struct ebt_u_entries *entries, *entries2;
@@ -832,7 +839,7 @@ int get_hooknr(char* arg)
}
// yup, print out help
-void print_help()
+static void print_help()
{
struct ebt_u_match_list *m_l;
struct ebt_u_watcher_list *w_l;
@@ -857,6 +864,10 @@ void print_help()
"--new-chain -N chain : Create a user defined chain\n"
"--rename-chain -E old new : Rename a chain\n"
"--delete-chain -X chain : Delete a user defined chain\n"
+"--atomic-commit file : update the kernel w/ the table contained in file\n"
+"--atomic-init file : put the initial kernel table into file\n"
+"--atomic-save file : put the current kernel table into file\n"
+"--atomic file : write changes to file instead of kernel\n"
"Options:\n"
"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
"--src -s [!] address[/mask]: source mac address\n"
@@ -1327,7 +1338,7 @@ static void delete_rule(int rule_nr)
}
// execute command Z
-void zero_counters(int zerochain)
+static void zero_counters(int zerochain)
{
if (zerochain == -1) {
@@ -1498,7 +1509,7 @@ int getmac_and_mask(char *from, char *to, char *mask)
}
// executes the final_check() function for all extensions used by the rule
-void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
+static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
{
struct ebt_u_match_list *m_l;
struct ebt_u_watcher_list *w_l;
@@ -1526,7 +1537,7 @@ void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
}
// used for the -X command
-void check_for_references(int chain_nr)
+static void check_for_references(int chain_nr)
{
int i = -1, j;
struct ebt_u_entries *entries;
@@ -1606,6 +1617,7 @@ int main(int argc, char *argv[])
replace.flags = 0;
replace.selected_hook = -1;
replace.command = 'h';
+ replace.filename = NULL;
new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
if (!new_entry)
@@ -1614,7 +1626,8 @@ int main(int argc, char *argv[])
initialize_entry(new_entry);
// The scenario induced by this loop makes that:
- // '-t' and '-M' (if specified) have to come before '-A' and the like
+ // '-t' ,'-M' and --atomic (if specified) have to come
+ // before '-A' and the like
// getopt saves the day
while ((c = getopt_long(argc, argv,
@@ -2083,6 +2096,37 @@ int main(int argc, char *argv[])
print_error("--Lx not compatible with --Ln");
replace.flags |= LIST_X;
break;
+ case 8 : // atomic-commit
+ replace.command = c;
+ if (replace.flags & OPT_COMMAND)
+ print_error("Multiple commands not allowed");
+ replace.flags |= OPT_COMMAND;
+ replace.filename = (char *)malloc(strlen(optarg) + 1);
+ strcpy(replace.filename, optarg);
+ // get the information from the file
+ get_table(&replace);
+ replace.num_counters = 0;
+ free(replace.filename);
+ replace.filename = NULL;
+ break;
+ case 7 : // atomic-init
+ case 10: // atomic-save
+ replace.command = c;
+ if (replace.flags & OPT_COMMAND)
+ print_error("Multiple commands not allowed");
+ replace.flags |= OPT_COMMAND;
+ if ( !(table = find_table(replace.name)) )
+ print_error("Bad table name");
+ if (get_table(&replace)) {
+ ebtables_insmod("ebtables", modprobe);
+ if (get_table(&replace))
+ print_error("can't initialize ebtables "
+ "table %s", replace.name);
+ }
+ case 9 : // atomic
+ replace.filename = (char *)malloc(strlen(optarg) + 1);
+ strcpy(replace.filename, optarg);
+ break;
default:
// is it a target option?
@@ -2212,7 +2256,7 @@ check_extension:
}
} else if (replace.command == 'D')
delete_rule(rule_nr);
- // commands -N, -E, -X fall through
+ // commands -N, -E, -X, --atomic-commit fall through
if (table->check)
table->check(&replace);