/* * BIRD -- Firewall Protocol Configuration * * (c) 2011 Alexander V. Chernikov <melifaro at 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, };