diff options
author | Jo-Philipp Wich <jow@openwrt.org> | 2009-12-20 02:38:13 +0000 |
---|---|---|
committer | Jo-Philipp Wich <jow@openwrt.org> | 2009-12-20 02:38:13 +0000 |
commit | d77076aa1653133e78619351ed41f721d4f59dd2 (patch) | |
tree | f7342a8a8f99ac0c082a144d305451c84e99f793 /contrib/fwd/src/fwd.c | |
parent | 19980872755027ab9fe3ca514d2053ab7b2a4c70 (diff) |
contrib/fwd: multi-call binary, iface monitoring, initial ipc integration
Diffstat (limited to 'contrib/fwd/src/fwd.c')
-rw-r--r-- | contrib/fwd/src/fwd.c | 268 |
1 files changed, 256 insertions, 12 deletions
diff --git a/contrib/fwd/src/fwd.c b/contrib/fwd/src/fwd.c index 903834b104..0b25cb0381 100644 --- a/contrib/fwd/src/fwd.c +++ b/contrib/fwd/src/fwd.c @@ -22,11 +22,53 @@ #include "fwd_rules.h" #include "fwd_config.h" #include "fwd_xtables.h" +#include "fwd_ipc.h" +#include "fwd_utils.h" -int main(int argc, const char *argv[]) +static void fwd_foreach_network( + struct fwd_handle *h, + void (*cb)(struct fwd_handle *h, struct fwd_network *net) +) { + struct fwd_data *data; + struct fwd_network *net; + + for( data = h->conf; data; data = data->next ) + { + if( data->type != FWD_S_ZONE ) + continue; + + for( net = data->section.zone.networks; net; net = net->next ) + cb(h, net); + } +} + +static void fwd_addif_all_cb(struct fwd_handle *h, struct fwd_network *net) +{ + fwd_ipt_addif(h, net->name); +} + +static void fwd_delif_all_cb(struct fwd_handle *h, struct fwd_network *net) +{ + fwd_ipt_delif(h, net->name); +} + +#define fwd_addif_all(h) fwd_foreach_network(h, fwd_addif_all_cb) +#define fwd_delif_all(h) fwd_foreach_network(h, fwd_delif_all_cb) + + +static int fwd_server_main(int argc, const char *argv[]) { struct fwd_handle *h; + struct fwd_network *net; + struct fwd_addr *addrs; + struct fwd_data *data; + struct fwd_cidr *addr_old, *addr_new; + struct sigaction sa; + int unix_client; + + sa.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sa, NULL); if( getuid() > 0 ) fwd_fatal("Need root permissions!"); @@ -34,31 +76,233 @@ int main(int argc, const char *argv[]) if( !(h = fwd_alloc_ptr(struct fwd_handle)) ) fwd_fatal("Out of memory"); - if( !(h->conf = fwd_read_config()) ) - fwd_fatal("Failed to read configuration"); - if( (h->rtnl_socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1 ) fwd_fatal("Failed to create AF_NETLINK socket (%m)"); - if( !(h->addrs = fwd_get_addrs(h->rtnl_socket, AF_INET)) ) - fwd_fatal("Failed to issue RTM_GETADDR (%m)"); + if( (h->unix_socket = fwd_ipc_listen()) == -1 ) + fwd_fatal("Failed to create AF_UNIX socket (%m)"); + + if( !(h->conf = fwd_read_config(h)) ) + fwd_fatal("Failed to read configuration"); + + fwd_log_init(); fwd_ipt_build_ruleset(h); + fwd_addif_all(h); + + while(1) + { + if( (addrs = fwd_get_addrs(h->rtnl_socket, AF_INET)) != NULL ) + { + for( data = h->conf; data; data = data->next ) + { + if( data->type != FWD_S_ZONE ) + continue; + + for( net = data->section.zone.networks; net; net = net->next ) + { + addr_new = fwd_lookup_addr(addrs, net->ifname); + addr_old = net->addr; + + if( !fwd_empty_cidr(addr_new) && fwd_empty_cidr(addr_old) ) + { + printf("IFUP[%s]\n", net->ifname); + fwd_update_cidr(addr_old, addr_new); + fwd_ipt_addif(h, net->name); + } + else if( fwd_empty_cidr(addr_new) && !fwd_empty_cidr(addr_old) ) + { + printf("IFDOWN[%s]\n", net->ifname); + fwd_update_cidr(addr_old, NULL); + fwd_ipt_delif(h, net->name); + } + else if( ! fwd_equal_cidr(addr_old, addr_new) ) + { + printf("IFCHANGE[%s]\n", net->ifname); + fwd_update_cidr(addr_old, addr_new); + fwd_ipt_chgif(h, net->name); + } + } + } + + fwd_free_addrs(addrs); + } + + + if( (unix_client = fwd_ipc_accept(h->unix_socket)) > -1 ) + { + struct fwd_ipc_msg msg; + memset(&msg, 0, sizeof(struct fwd_ipc_msg)); + + while( fwd_ipc_recvmsg(unix_client, &msg, sizeof(struct fwd_ipc_msg)) > 0 ) + { + fwd_log_info("Got message [%i]", msg.type); + + switch(msg.type) + { + case FWD_IPC_FLUSH: + fwd_log_info("Flushing rules ..."); + fwd_ipt_clear_ruleset(h); + fwd_ipc_sendtype(unix_client, FWD_IPC_OK); + break; + + case FWD_IPC_BUILD: + fwd_log_info("Building rules ..."); + fwd_ipt_clear_ruleset(h); + fwd_ipt_build_ruleset(h); + fwd_addif_all(h); + fwd_ipc_sendtype(unix_client, FWD_IPC_OK); + break; + + case FWD_IPC_RELOAD: + if( (data = fwd_read_config(h)) != NULL ) + { + fwd_log_info("Flushing rules ..."); + fwd_ipt_clear_ruleset(h); + fwd_free_config(h->conf); + h->conf = data; + fwd_log_info("Building rules ..."); + fwd_ipt_build_ruleset(h); + fwd_addif_all(h); + fwd_ipc_sendtype(unix_client, FWD_IPC_OK); + } + else + { + fwd_log_err("Cannot reload configuration!"); + fwd_ipc_sendtype(unix_client, FWD_IPC_ERROR); + } + break; + + case FWD_IPC_ADDIF: + case FWD_IPC_DELIF: + if( strlen(msg.data.network) > 0 ) + { + fwd_ipt_delif(h, msg.data.network); + + if( msg.type == FWD_IPC_ADDIF ) + fwd_ipt_addif(h, msg.data.network); + + fwd_ipc_sendtype(unix_client, FWD_IPC_OK); + } + else + { + fwd_log_err("No network name provided!"); + fwd_ipc_sendtype(unix_client, FWD_IPC_ERROR); + } + break; - fwd_ipt_addif(h, "lan"); - fwd_ipt_addif(h, "wan"); + case FWD_IPC_OK: + case FWD_IPC_ERROR: + break; + } + } - sleep(1); + fwd_ipc_shutdown(unix_client); + } - fwd_ipt_delif(h, "wan"); - fwd_ipt_delif(h, "lan"); + sleep(1); + } + + fwd_delif_all(h); fwd_ipt_clear_ruleset(h); close(h->rtnl_socket); fwd_free_config(h->conf); - fwd_free_addrs(h->addrs); fwd_free_ptr(h); return 0; } + +static void fwd_client_usage(const char *msg) +{ + printf( + "%s\n\n" + "Usage:\n" + " fw flush\n" + " Flush all rules in the firewall and reset policy\n\n" + " fw build\n" + " Rebuild firewall rules\n\n" + " fw reload\n" + " Reload configuration and rebuild firewall rules\n\n" + " fw addif {network}\n" + " Add rules for given network\n\n" + " fw delif {network}\n" + " Remove rules for given network\n\n" + "", msg + ); + + exit(1); +} + +static int fwd_client_main(int argc, const char *argv[]) +{ + int unix_server; + struct fwd_ipc_msg msg; + enum fwd_ipc_msgtype type; + + if( argc < 2 ) + fwd_client_usage("Command required"); + + if( (unix_server = fwd_ipc_connect()) < 0 ) + fwd_fatal("Cannot connect to server instance (%m)"); + + + memset(&msg, 0, sizeof(struct fwd_ipc_msg)); + + if( !strcmp(argv[1], "flush") ) + type = FWD_IPC_FLUSH; + + else if( !strcmp(argv[1], "build") ) + type = FWD_IPC_BUILD; + + else if( !strcmp(argv[1], "reload") ) + type = FWD_IPC_RELOAD; + + else if( !strcmp(argv[1], "addif") || !strcmp(argv[1], "delif") ) + { + if( argc < 3 ) + fwd_client_usage("The command requires a parameter."); + + type = strcmp(argv[1], "addif") ? FWD_IPC_DELIF : FWD_IPC_ADDIF; + strncpy(msg.data.network, argv[2], sizeof(msg.data.network)); + } + + else + fwd_client_usage("Invalid command given."); + + msg.type = type; + fwd_ipc_sendmsg(unix_server, &msg, sizeof(struct fwd_ipc_msg)); + + memset(&msg, 0, sizeof(struct fwd_ipc_msg)); + + while( fwd_ipc_recvmsg(unix_server, &msg, sizeof(struct fwd_ipc_msg)) == 0 ) + continue; + + switch(msg.type) + { + case FWD_IPC_OK: + printf("Success\n"); + break; + + case FWD_IPC_ERROR: + printf("The server reported an error, check logread!\n"); + break; + + default: + fwd_fatal("Unexpected response type %i", msg.type); + } + + fwd_ipc_shutdown(unix_server); + + return 0; +} + +int main(int argc, const char *argv[]) +{ + if( strstr(argv[0], "fwd") ) + return fwd_server_main(argc, argv); + else + return fwd_client_main(argc, argv); +} + |