diff options
Diffstat (limited to 'proto/firewall/firewall.c')
-rw-r--r-- | proto/firewall/firewall.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/proto/firewall/firewall.c b/proto/firewall/firewall.c new file mode 100644 index 00000000..108cc075 --- /dev/null +++ b/proto/firewall/firewall.c @@ -0,0 +1,201 @@ +/* + * BIRD -- Firewall Protocol Configuration + * + * (c) 2011 Alexander V. Chernikov <melifaro@FreeBSD.org> + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +/** + * DOC: Firewall + * + * Firewall protocol is very simple. It adds or removes exported routes to given firewall + * table with zero (or filter-specified) value. Table can be flushed on startup to + * avoid error messages on bird restart. + */ + +#undef LOCAL_DEBUG + +#include "nest/bird.h" +#include "nest/iface.h" +#include "nest/protocol.h" +#include "nest/route.h" +#include "conf/conf.h" +#include "filter/filter.h" +#include "lib/string.h" + +#include "firewall.h" + +static int init_done = 0; + +static void +firewall_collect(void) +{ + memset(&firewalls, 0, sizeof(firewalls)); + log(L_DEBUG "Initializing firewalls.."); +#ifdef CONFIG_FIREWALL_IPFW + firewalls[FWTYPE_IPFW] = &fw_ipfw; + log(L_DEBUG "IPFW.."); +#endif +#ifdef CONFIG_FIREWALL_PF + firewalls[FWTYPE_PF] = &fw_pf; + log(L_DEBUG "PF.."); +#endif +#ifdef CONFIG_FIREWALL_IPSET + firewalls[FWTYPE_IPSET] = &fw_ipset; + log(L_DEBUG "IPSET.."); +#endif +} + +static void +firewall_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs) +{ + struct firewall_proto *p = (struct firewall_proto *) P; + u32 prefix_val; + char prefix_data[10]; + + if (!new && !old) + return; + + prefix_val = ea_get_int(attrs, EA_FIREWALL_VALUE, 0); + + if (prefix_val) + bsnprintf(prefix_data, sizeof(prefix_data), "%u", prefix_val); + else + prefix_data[0] = '\0'; + + DBG("Got prefix %I/%d with data '%s'\n", n->n.prefix, n->n.pxlen, prefix_data); + + if (old && new && p->fw->fw_replace) + { + if (!p->fw->fw_replace(p->fwdata, n, prefix_data)) + log(L_ERR "Replacing prefix %I/%d with data '%S' failed", n->n.prefix, n->n.pxlen, prefix_data); + return; + } + + if (old) + if (!p->fw->fw_del(p->fwdata, n)) + log(L_ERR "Removing prefix %I/%d failed", n->n.prefix, n->n.pxlen); + + if (new) + if (!p->fw->fw_add(p->fwdata, n, prefix_data)) + log(L_ERR "Adding prefix %I/%d with data '%s' failed", n->n.prefix, n->n.pxlen, prefix_data); + +} + +static int +firewall_start(struct proto *P) +{ + struct firewall_proto *p = (struct firewall_proto *) P; + struct firewall_config *c = (struct firewall_config *)P->cf; + void *fwdata; + + if ((fwdata = p->fw->fw_init(P, c->fwtable)) == NULL) + return PS_DOWN; + + p->fwdata = fwdata; + + /* Flush table if needed */ + if ((c->flush_start) && (p->fw->fw_flush)) + if (!p->fw->fw_flush(fwdata)) + { + log(L_ERR "flush failed for table %s", c->fwtable); + return PS_DOWN; + } + + return PS_UP; +} + +static int +firewall_shutdown(struct proto *P) +{ + struct firewall_proto *p = (struct firewall_proto *) P; + struct firewall_config *c = (struct firewall_config *)P->cf; + + log(L_DEBUG, "Shutdown requested"); + + /* Flush table if needed */ + if ((c->flush_shutdown) && (p->fw->fw_flush)) + if (!p->fw->fw_flush(p->fwdata)) + log(L_ERR "flush failed for table %s", c->fwtable); + + p->fw->fw_shutdown(p->fwdata); + + return PS_DOWN; +} + +static struct proto * +firewall_init(struct proto_config *C) +{ + struct firewall_config *c = (struct firewall_config *) C; + struct proto *P = proto_new(C, sizeof(struct firewall_proto)); + struct firewall_proto *p = (struct firewall_proto *) P; + + /* Configure firewalls */ + if (!init_done) + { + init_done = 1; + firewall_collect(); + } + + p->fwtype = c->fwtype; + p->fw = firewalls[p->fwtype]; + P->accept_ra_types = RA_OPTIMAL; + P->rt_notify = firewall_rt_notify; + + return P; +} + +static int +firewall_reconfigure(struct proto *P, struct proto_config *new) +{ + struct firewall_config *o = (struct firewall_config *) P->cf; + struct firewall_config *n = (struct firewall_config *) new; + + if ((o->fwtype != n->fwtype) || (strcmp(o->fwtable, n->fwtable))) + return 0; + + return 1; +} + +static void +firewall_copy_config(struct proto_config *dest, struct proto_config *src) +{ + /* Just a shallow copy, not many items here */ + proto_copy_rest(dest, src, sizeof(struct firewall_config)); +} + +static void +firewall_get_status(struct proto *P, byte *buf) +{ + struct firewall_config *c = (struct firewall_config *) P->cf; + + bsprintf(buf, "Table [%s]", c ? c->fwtable : "none"); +} + +static int +firewall_get_attr(eattr * a, byte * buf, int buflen UNUSED) +{ + switch (a->id) + { + case EA_FIREWALL_VALUE: + bsprintf(buf, "fw_value"); + return GA_NAME; + default: + return GA_UNKNOWN; + } +} + + +struct protocol proto_firewall = { + name: "Firewall", + template: "fw%d", + class: PROTOCOL_FIREWALL, + init: firewall_init, + start: firewall_start, + shutdown: firewall_shutdown, + reconfigure: firewall_reconfigure, + copy_config: firewall_copy_config, + get_status: firewall_get_status, + get_attr: firewall_get_attr, +}; |