[PATCH 1/1] * Add draft support for firewall protocol
--- configure.in | 3 +- nest/proto.c | 3 + nest/protocol.h | 2 +- proto/firewall/Doc | 1 + proto/firewall/Makefile | 6 ++ proto/firewall/config.Y | 71 +++++++++++++++++ proto/firewall/firewall.c | 152 +++++++++++++++++++++++++++++++++++++ proto/firewall/firewall.h | 48 ++++++++++++ sysdep/autoconf.h.in | 5 + sysdep/bsd/Modules | 1 + sysdep/bsd/fw.c | 185 +++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 475 insertions(+), 2 deletions(-) create mode 100644 proto/firewall/Doc create mode 100644 proto/firewall/Makefile create mode 100644 proto/firewall/config.Y create mode 100644 proto/firewall/firewall.c create mode 100644 proto/firewall/firewall.h create mode 100644 sysdep/bsd/fw.c diff --git a/configure.in b/configure.in index 46a6ecd..48d8968 100644 --- a/configure.in +++ b/configure.in @@ -47,7 +47,7 @@ if test "$enable_ipv6" = yes ; then else ip=ipv4 SUFFIX6="" - all_protocols=bgp,ospf,pipe,rip,static + all_protocols=bgp,ospf,pipe,rip,static,firewall fi if test "$with_protocols" = all ; then @@ -130,6 +130,7 @@ else ipv6:freebsd*) sysdesc=bsd-v6 ;; ipv4:freebsd*) sysdesc=bsd + AC_DEFINE(CONFIG_FIREWALL_IPFW, 1) ;; ipv6:kfreebsd*) sysdesc=bsd-v6 ;; diff --git a/nest/proto.c b/nest/proto.c index d55c348..85bdb19 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -632,6 +632,9 @@ protos_build(void) #ifdef CONFIG_BGP proto_build(&proto_bgp); #endif +#ifdef CONFIG_FIREWALL + proto_build(&proto_firewall); +#endif proto_pool = rp_new(&root_pool, "Protocols"); proto_flush_event = ev_new(proto_pool); proto_flush_event->hook = proto_flush_all; diff --git a/nest/protocol.h b/nest/protocol.h index a7518c2..d09a556 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -73,7 +73,7 @@ void protos_dump_all(void); extern struct protocol proto_device, proto_radv, proto_rip, proto_static, - proto_ospf, proto_pipe, proto_bgp; + proto_ospf, proto_pipe, proto_bgp, proto_firewall; /* * Routing Protocol Instance diff --git a/proto/firewall/Doc b/proto/firewall/Doc new file mode 100644 index 0000000..5779342 --- /dev/null +++ b/proto/firewall/Doc @@ -0,0 +1 @@ +S firewall.c diff --git a/proto/firewall/Makefile b/proto/firewall/Makefile new file mode 100644 index 0000000..a322ab6 --- /dev/null +++ b/proto/firewall/Makefile @@ -0,0 +1,6 @@ +source=firewall.c +root-rel=../../ +dir-name=proto/firewall + +include ../../Rules + diff --git a/proto/firewall/config.Y b/proto/firewall/config.Y new file mode 100644 index 0000000..bbe314a --- /dev/null +++ b/proto/firewall/config.Y @@ -0,0 +1,71 @@ +/* + * 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. + */ + +CF_HDR + +#include "proto/firewall/firewall.h" + +CF_DEFINES + +#define FIREWALL_CFG ((struct firewall_config *) this_proto) + +CF_DECLS + +CF_KEYWORDS(FIREWALL, FWTABLE, FWTYPE, IPFW, PF, IPTABLES, FLUSH) + +%type <i> firewall_type +CF_GRAMMAR + +CF_ADDTO(proto, firewall_proto '}') + +firewall_proto_start: proto_start FIREWALL { + this_proto = proto_config_new(&proto_firewall, sizeof(struct firewall_config), $1); + this_proto->preference = 0; + } + ; + +firewall_proto: + firewall_proto_start proto_name '{' + | firewall_proto proto_item ';' + | firewall_proto firewall_proto_item ';' + ; + +firewall_proto_item: + FWTYPE firewall_type { + switch ($2) + { +#ifdef CONFIG_FIREWALL_IPFW + case FWTYPE_IPFW: + break; +#endif +#ifdef CONFIG_FIREWALL_PF + case FWTYPE_PF: + break; +#endif +#ifdef CONFIG_FIREWALL_IPTABLES + case FWTYPE_IPTABLES: + break; +#endif + default: + cf_error("firewall type is not supported by your OS"); + } + FIREWALL_CFG->fwtype = $2; + }; + | FWTABLE TEXT { FIREWALL_CFG->fwtable = $2; } + | FLUSH { FIREWALL_CFG->flush = 1; } + ; + +firewall_type: + IPFW { $$ = FWTYPE_IPFW; } + | PF { $$ = FWTYPE_PF; } + | IPTABLES { $$ = FWTYPE_IPTABLES; } + ; + +CF_CODE + +CF_END diff --git a/proto/firewall/firewall.c b/proto/firewall/firewall.c new file mode 100644 index 0000000..070b608 --- /dev/null +++ b/proto/firewall/firewall.c @@ -0,0 +1,152 @@ +/* + * 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_IPTABLES + firewalls[FWTYPE_IPTABLES] = &fw_iptables; + log(L_DEBUG "IPTABLES.."); +#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; + + if (!new && !old) + return; + + char *prefix_data = ""; + + DBG("Got prefix %I/%d with data '%s'\n", n->n.prefix, n->n.pxlen, prefix_data); + + 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; + + if ((c->flush) && (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 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"); +} + + +struct protocol proto_firewall = { + name: "Firewall", + template: "fw%d", + init: firewall_init, + start: firewall_start, + reconfigure: firewall_reconfigure, + copy_config: firewall_copy_config, + get_status: firewall_get_status, +}; diff --git a/proto/firewall/firewall.h b/proto/firewall/firewall.h new file mode 100644 index 0000000..c08cb73 --- /dev/null +++ b/proto/firewall/firewall.h @@ -0,0 +1,48 @@ +/* + * BIRD -- Table-to-Table Routing Protocol a.k.a Pipe + * + * (c) 1999 Martin Mares <mj@ucw.cz> + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_FIREWALL_H_ +#define _BIRD_FIREWALL_H_ + +#define FWTYPE_IPFW 0 +#define FWTYPE_PF 1 +#define FWTYPE_IPTABLES 2 + +#define FWTYPE_MAX 3 + +struct firewall_config { + struct proto_config c; + int fwtype; /* Firewall type */ + char *fwtable; /* Firewall table to write to */ + int flush; /* Do table flush on startup? */ +}; + +struct firewall_control { + int fwtype; /* Firewall type */ + char *description; /* Firewall description */ + void *(*fw_init)(struct proto *, char *); /* Init firewall instance */ + void (*fw_shutdown)(void *); /* Shutdown firewall instance */ + int (*fw_flush)(void *); /* Flush firewall table */ + int (*fw_add)(void *, net *, char *); /* Add record to table */ + int (*fw_del)(void *, net *); /* Remove record from table */ +}; + +struct firewall_control * firewalls[FWTYPE_MAX]; + +struct firewall_proto { + struct proto p; + int fwtype; /* Firewall type */ + struct firewall_control *fw; /* Pointer to configured protocol type */ + void *fwdata; /* Firewall instance private data */ +}; + +extern struct protocol proto_firewall; + +extern struct firewall_control fw_ipfw, fw_pf, fw_iptables; + +#endif diff --git a/sysdep/autoconf.h.in b/sysdep/autoconf.h.in index d029e2a..1980d20 100644 --- a/sysdep/autoconf.h.in +++ b/sysdep/autoconf.h.in @@ -42,6 +42,11 @@ #undef CONFIG_BGP #undef CONFIG_OSPF #undef CONFIG_PIPE +#undef CONFIG_FIREWALL + +#undef CONFIG_FIREWALL_IPFW +#undef CONFIG_FIREWALL_PF +#undef CONFIG_FIREWALL_IPTABLES /* We have <syslog.h> and syslog() */ #undef HAVE_SYSLOG diff --git a/sysdep/bsd/Modules b/sysdep/bsd/Modules index 84abffd..77f26e3 100644 --- a/sysdep/bsd/Modules +++ b/sysdep/bsd/Modules @@ -4,3 +4,4 @@ sysio.h krt-set.h krt-sock.c krt-sock.h +fw.c diff --git a/sysdep/bsd/fw.c b/sysdep/bsd/fw.c new file mode 100644 index 0000000..b626e65 --- /dev/null +++ b/sysdep/bsd/fw.c @@ -0,0 +1,185 @@ +/* + * BIRD -- IPFW/PF manipulations + * + * (c) 2011 Alexander V. Chernikov <melifaro@FreeBSD.org> + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <ctype.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <errno.h> +#include <err.h> +#include <net/route.h> +#include <net/if.h> +#include <net/if_dl.h> + +#define LOCAL_DEBUG + +#include "nest/bird.h" +#include "nest/iface.h" +#include "nest/route.h" +#include "nest/protocol.h" +#include "nest/iface.h" +#include "lib/timer.h" +#include "lib/unix.h" +#include "lib/krt.h" +#include "lib/string.h" +#include "lib/socket.h" +#ifdef CONFIG_FIREWALL +#include "proto/firewall/firewall.h" +#ifdef CONFIG_FIREWALL_IPFW +#include "netinet/ip_fw.h" +#endif + +#ifdef CONFIG_FIREWALL_IPFW + +struct ipfw_priv { + int fd; /* file descriptor */ + int table; /* Table number */ + pool *pool; /* Protocol pool */ +}; + +int +ipfw_do_cmd(struct ipfw_priv *priv, int optname, void *optval, uintptr_t optlen) +{ + return setsockopt(priv->fd, IPPROTO_IP, optname, optval, optlen); +} + +void * +ipfw_fw_init(struct proto *p, char *table) +{ + pool *fwpool = p->pool; + int table_num = strtol(table, NULL, 10); + int fd; + + if ((table_num < 0) || (table_num > 127)) + { + log(L_ERR "ipfw table %d is not within possible range"); + return NULL; + } + + if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) + { + log(L_ERR "ipfw: error opering raw socket: %m"); + return NULL; + } + + struct ipfw_priv *priv = mb_alloc(fwpool, sizeof(struct ipfw_priv)); + + priv->table = table_num; + priv->pool = fwpool; + priv->fd = fd; + + DBG("Opened IPFW socked %d\n", priv->fd); + + return priv; +} + +void +ipfw_fw_shutdown(void *_priv) +{ + struct ipfw_priv *priv = _priv; + + if (priv->fd != -1) + close(priv->fd); + + mb_free(priv); +} + +int +ipfw_fw_flush(void *_priv) +{ + struct ipfw_priv *priv = _priv; + ipfw_table_entry ent; + + memset(&ent, 0, sizeof(ent)); + ent.tbl = priv->table; + + log(L_ERR "Flushing ipfw table %d", priv->table); + + if (ipfw_do_cmd(priv, IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) == -1) + { + log(L_ERR "Error flushing ipfw table %d: %m", priv->table); + return 0; + } + + return 1; +} + +int +ipfw_fw_add(void *_priv, net *n, char *prefixdata) +{ + struct ipfw_priv *priv = _priv; + ip_addr addr; + ipfw_table_entry ent; + + addr = n->n.prefix; + ipa_hton(addr); + + ent.masklen = n->n.pxlen; + memcpy(&ent.addr, &addr, sizeof(ip_addr)); + ent.value = strtol(prefixdata, NULL, 0); + ent.tbl = priv->table; + + + log(L_ERR "Adding %I/%d to ipfw table %d with value %s", n->n.prefix, n->n.pxlen, priv->table, prefixdata); + + if (ipfw_do_cmd(priv, IP_FW_TABLE_ADD, &ent, sizeof(ent)) == -1) + { + log(L_ERR "Error adding %I/%d to ipfw table %d: %m", n->n.prefix, n->n.pxlen, priv->table); + return 0; + } + + return 1; +} + +int +ipfw_fw_del(void *_priv, net *n) +{ + struct ipfw_priv *priv = _priv; + ip_addr addr; + ipfw_table_entry ent; + + addr = n->n.prefix; + ipa_hton(addr); + + ent.masklen = n->n.pxlen; + memcpy(&ent.addr, &addr, sizeof(ip_addr)); + ent.value = 0; + ent.tbl = priv->table; + + log(L_ERR "Removing %I/%d from ipfw table %d", n->n.prefix, n->n.pxlen, priv->table); + + if (ipfw_do_cmd(priv, IP_FW_TABLE_DEL, &ent, sizeof(ent)) == -1) + { + log(L_ERR "Error removing %I/%d from ipfw table %d: %m", n->n.prefix, n->n.pxlen, priv->table); + return 0; + } + + return 1; +} + +struct firewall_control fw_ipfw = { + fwtype: FWTYPE_IPFW, + description: "IPFW", + fw_init: ipfw_fw_init, + fw_shutdown: ipfw_fw_shutdown, + fw_flush: ipfw_fw_flush, + fw_add: ipfw_fw_add, + fw_del: ipfw_fw_del, +}; +#endif + +#endif + -- 1.7.3.2 --------------060202010104050107080409--
participants (1)
-
Alexander V. Chernikov