From f610486180e7ba5a0f7b7127edfdcfaf704353a1 Mon Sep 17 00:00:00 2001 From: Alexander V. Chernikov Date: Wed, 15 Aug 2012 16:09:21 +0000 Subject: [PATCH 1/1] Add firewall support v2 --- configure.in | 6 +- doc/bird.sgml | 34 ++++ nest/proto.c | 3 + nest/protocol.h | 2 +- nest/route.h | 3 +- proto/firewall/Doc | 1 + proto/firewall/Makefile | 6 + proto/firewall/config.Y | 77 +++++++++ proto/firewall/firewall.c | 198 ++++++++++++++++++++++ proto/firewall/firewall.h | 54 ++++++ sysdep/autoconf.h.in | 5 + sysdep/bsd/Modules | 1 + sysdep/bsd/fw.c | 404 +++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 791 insertions(+), 3 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 54993df..51b7cc2 100644 --- configure.in +++ configure.in @@ -51,7 +51,7 @@ if test "$enable_ipv6" = yes ; then else ip=ipv4 SUFFIX="" - all_protocols=bgp,ospf,pipe,rip,static + all_protocols=bgp,ospf,pipe,rip,static,firewall fi if test "$given_suffix" = yes ; then @@ -137,10 +137,13 @@ else ipv4:netbsd*) sysdesc=bsd CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" LDFLAGS="$LDFLAGS -L/usr/pkg/lib -R/usr/pkg/lib" + AC_DEFINE(CONFIG_FIREWALL_PF, 1) ;; ipv6:freebsd*) sysdesc=bsd-v6 ;; ipv4:freebsd*) sysdesc=bsd + AC_DEFINE(CONFIG_FIREWALL_IPFW, 1) + AC_DEFINE(CONFIG_FIREWALL_PF, 1) ;; ipv6:dragonfly*) sysdesc=bsd-v6 ;; @@ -153,6 +156,7 @@ else ipv6:openbsd*) sysdesc=bsd-v6 ;; ipv4:openbsd*) sysdesc=bsd + AC_DEFINE(CONFIG_FIREWALL_PF, 1) ;; *) AC_MSG_ERROR([Cannot determine correct system configuration. Please use --with-sysconfig to set it manually.]) ;; diff --git a/doc/bird.sgml b/doc/bird.sgml index 24bc302..a01ec99 100644 --- doc/bird.sgml +++ doc/bird.sgml @@ -2743,6 +2743,40 @@ protocol static { } +Firewall + +

Firewall protocol doesn't communicate with any network devices, +but instead it allows you to add announced prefixes to given firewall table. +At the moment IPFW and PF are supported. One can also specify special integer tag +that can be passed as argument to IPFW table. Any number of instances can be configured. + +

Firewall protocol does not have many configuration options. + + + fwtype pf|ipfw Select firewall type. + fwtable Specifies firewall table name. + keep on startup|shutdownDo not flush table on protocol startup or shutdown. + keep alwaysDo not flush table on protocol startup and shutdown. + + +

Firewall defines single route attribute: + + + int Value that can be passed with prefix. + Value is unsigned 4-byte integer. It can be set when importing routes from the other + protocols or on protocol export. + + +

Example firewall config might look like this: + +

+protocol firewall { + table testable; # Connect to a non-default routing table + fwtype ipfw; # Use IPFW as backend + fwtable "2"; # Use table 2 + export filter { fw_value = 125; accept; }; # Set value 125 for all prefixes +} + Conclusions Future work diff --git a/nest/proto.c b/nest/proto.c index 53d3f1a..78d7600 100644 --- nest/proto.c +++ nest/proto.c @@ -707,6 +707,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_loop; diff --git a/nest/protocol.h b/nest/protocol.h index 11fcb16..c7275d6 100644 --- nest/protocol.h +++ nest/protocol.h @@ -75,7 +75,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/nest/route.h b/nest/route.h index 524e69b..f3062a2 100644 --- nest/route.h +++ nest/route.h @@ -361,7 +361,8 @@ typedef struct eattr { #define EAP_RIP 2 /* RIP */ #define EAP_OSPF 3 /* OSPF */ #define EAP_KRT 4 /* Kernel route attributes */ -#define EAP_MAX 5 +#define EAP_FIREWALL 5 /* Abstact firewall interface */ +#define EAP_MAX 6 #define EA_CODE(proto,id) (((proto) << 8) | (id)) #define EA_PROTO(ea) ((ea) >> 8) diff --git a/proto/firewall/Doc b/proto/firewall/Doc new file mode 100644 index 0000000..5779342 --- /dev/null +++ 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 +++ 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..aefc606 --- /dev/null +++ proto/firewall/config.Y @@ -0,0 +1,77 @@ +/* + * BIRD -- Firewall Protocol Configuration + * + * (c) 2011 Alexander V. Chernikov + * + * 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, FW_VALUE, IPFW, PF, IPSET, KEEP, ON, STARTUP, SHUTDOWN, ALWAYS) + +%type 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_CFG->flush_start = 1; + FIREWALL_CFG->flush_shutdown = 1; + } + ; + +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_IPSET + case FWTYPE_IPSET: + break; +#endif + default: + cf_error("firewall type is not supported by your OS/build"); + } + FIREWALL_CFG->fwtype = $2; + }; + | FWTABLE TEXT { FIREWALL_CFG->fwtable = $2; } + | KEEP ON STARTUP { FIREWALL_CFG->flush_start = 0; } + | KEEP ON SHUTDOWN { FIREWALL_CFG->flush_shutdown = 0; } + | KEEP ALWAYS { FIREWALL_CFG->flush_start = 0; FIREWALL_CFG->flush_shutdown = 0; } + ; + +firewall_type: + IPFW { $$ = FWTYPE_IPFW; } + | PF { $$ = FWTYPE_PF; } + | IPSET { $$ = FWTYPE_IPSET; } + ; + +CF_ADDTO(dynamic_attr, FW_VALUE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_FIREWALL_VALUE); }) + +CF_CODE + +CF_END diff --git a/proto/firewall/firewall.c b/proto/firewall/firewall.c new file mode 100644 index 0000000..e447470 --- /dev/null +++ proto/firewall/firewall.c @@ -0,0 +1,198 @@ +/* + * BIRD -- Firewall Protocol Configuration + * + * (c) 2011 Alexander V. Chernikov + * + * 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; +struct rate_limit rl_fw_err; + +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) + { + p->fw->fw_replace(p->fwdata, n, prefix_data); + return; + } + + if (old) + p->fw->fw_del(p->fwdata, n); + + if (new) + p->fw->fw_add(p->fwdata, n, 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_START; + + 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_START; + } + + 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->fwtable); +} + +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", + attr_class: EAP_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, +}; diff --git a/proto/firewall/firewall.h b/proto/firewall/firewall.h new file mode 100644 index 0000000..c97ed38 --- /dev/null +++ proto/firewall/firewall.h @@ -0,0 +1,54 @@ +/* + * BIRD -- Firewall Protocol Configuration + * + * (c) 2011 Alexander V. Chernikov + * + * 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_IPSET 2 + +#define FWTYPE_MAX 3 + +#define EA_FIREWALL_VALUE EA_CODE(EAP_FIREWALL, 0) + +struct firewall_config { + struct proto_config c; + int fwtype; /* Firewall type */ + char *fwtable; /* Firewall table to write to */ + int flush_start; /* Do table flush on startup? */ + int flush_shutdown; /* Do table flush on shutdown? */ +}; + +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 */ + int (*fw_replace)(void *, net *, char *); /* Replace record. Optional */ +}; + +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_ipset; +extern struct rate_limit rl_fw_err; +#define FW_ERR(x, y...) log_rl(&rl_fw_err, L_ERR x, ##y) + +#endif diff --git a/sysdep/autoconf.h.in b/sysdep/autoconf.h.in index ac6f7a8..2d5af5c 100644 --- sysdep/autoconf.h.in +++ 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_IPSET /* We have and syslog() */ #undef HAVE_SYSLOG diff --git a/sysdep/bsd/Modules b/sysdep/bsd/Modules index 3729587..0607321 100644 --- sysdep/bsd/Modules +++ sysdep/bsd/Modules @@ -1,3 +1,4 @@ krt-sock.c krt-sys.h sysio.h +fw.c diff --git a/sysdep/bsd/fw.c b/sysdep/bsd/fw.c new file mode 100644 index 0000000..e841e06 --- /dev/null +++ sysdep/bsd/fw.c @@ -0,0 +1,404 @@ +/* + * BIRD -- IPFW/PF manipulations + * + * (c) 2011 Alexander V. Chernikov + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef 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_PF +#include "net/pfvar.h" +#endif + +#ifdef CONFIG_FIREWALL_IPFW + +int ipfw_fd = -1; +int ipfw_instance_count = 0; + +struct ipfw_priv { + int table; /* Table number */ + pool *pool; /* Protocol pool */ +}; + +int +ipfw_do_cmd(int optname, void *optval, uintptr_t optlen) +{ + return setsockopt(ipfw_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 tables_max; + size_t len = sizeof(tables_max); + + if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len, NULL, 0) == -1) + { + log(L_ERR "Error getting maximum ipfw table count"); + tables_max = IPFW_TABLES_MAX; + } + DBG("ipfw maximum table count set to %d\n", tables_max); + + if ((table_num < 0) || (table_num >= tables_max)) + { + log(L_ERR "ipfw table %d is not within possible range (0..%d)", table_num, tables_max); + return NULL; + } + + if (ipfw_fd == -1) + { + if ((ipfw_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) + { + log(L_ERR "ipfw: error opering raw socket: %m"); + return NULL; + } + DBG("Opened IPFW socked %d\n", ipfw_fd); + } + + struct ipfw_priv *priv = mb_alloc(fwpool, sizeof(struct ipfw_priv)); + + priv->table = table_num; + priv->pool = fwpool; + + ipfw_instance_count++; + + return priv; +} + +void +ipfw_fw_shutdown(void *_priv UNUSED) +{ + if (--ipfw_instance_count == 0) + { + DBG("Closing ipfw socket %d\n", ipfw_fd); + close(ipfw_fd); + ipfw_fd = -1; + } +} + +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_DEBUG "Flushing ipfw table %d", priv->table); + + if (ipfw_do_cmd(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; + + DBG("Adding %I/%d to ipfw table %d with value %s\n", n->n.prefix, n->n.pxlen, priv->table, prefixdata); + + if (ipfw_do_cmd(IP_FW_TABLE_ADD, &ent, sizeof(ent)) == -1) + { + FW_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; + + DBG("Removing %I/%d from ipfw table %d\n", n->n.prefix, n->n.pxlen, priv->table); + + if (ipfw_do_cmd(IP_FW_TABLE_DEL, &ent, sizeof(ent)) == -1) + { + FW_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 + +#ifdef CONFIG_FIREWALL_PF + +#define PF_DEVNAME "/dev/pf" +int pf_fd = -1; +int pf_instance_count = 0; + +struct pf_priv { + struct pfr_table table; /* PF table structure */ + pool *pool; /* Protocol pool */ +}; + +#define pf_tablename table.pfrt_name + +int +pf_do_cmd(struct pfr_table *tbl, unsigned long cmd, void *buffer, int esize, int items, int *nadd, int *ndel, int flags) +{ + struct pfioc_table io; + + bzero(&io, sizeof(io)); + io.pfrio_flags = flags; + if (tbl) + io.pfrio_table = *tbl; + io.pfrio_buffer = buffer; + io.pfrio_esize = esize; + io.pfrio_size = items; + + /* DBG("Doing PF ioctl %X for table %s on fd %d\n", cmd, tbl ? tbl->pfrt_name : "NULL", pf_fd); */ + if (ioctl(pf_fd, cmd, &io)) + return 0; + + if (nadd) + *nadd = io.pfrio_nadd; + if (ndel) + *ndel = io.pfrio_ndel; + + return 1; +} + +void * +pf_fw_init(struct proto *p, char *table) +{ + pool *fwpool = p->pool; + struct pfr_table pf_table; + int nadd = 0; + + if (strlen(table) > PF_TABLE_NAME_SIZE) + { + log(L_ERR "PF table name too long, max %d", PF_TABLE_NAME_SIZE); + return NULL; + } + + memset(&pf_table, 0, sizeof(pf_table)); + + if (pf_fd == -1) + { + if ((pf_fd = open(PF_DEVNAME, O_RDWR)) == -1) + { + log(L_ERR "pf: error opening %s: %m", PF_DEVNAME); + return NULL; + } + + DBG("Opened PF socked %d\n", pf_fd); + } + + strcpy(pf_table.pfrt_name, table); + pf_table.pfrt_flags |= PFR_TFLAG_PERSIST; + if (!pf_do_cmd(NULL, DIOCRADDTABLES, &pf_table, sizeof(pf_table), 1, &nadd, NULL, 0)) + { + log(L_ERR "Error creating PF table %s: %m", table); + if (pf_instance_count == 0) + { + log(L_ERR "Closing PF socket"); + close(pf_fd); + pf_fd = -1; + } + return NULL; + } + DBG("PF table %s created\n", table); + /* Remove persistent flag */ + pf_table.pfrt_flags = 0; + + struct pf_priv *priv = mb_alloc(fwpool, sizeof(struct pf_priv)); + + priv->table = pf_table; + priv->pool = fwpool; + + pf_instance_count++; + + return priv; +} + +void +pf_fw_shutdown(void *_priv UNUSED) +{ + if (--pf_instance_count == 0) + { + DBG("Closing PF socket %d\n", pf_fd); + close(pf_fd); + pf_fd = -1; + } +} + +int +pf_fw_flush(void *_priv) +{ + struct pf_priv *priv = _priv; + int ndel; + + log(L_DEBUG "Flushing PF table %s", priv->pf_tablename); + + if (!pf_do_cmd(&priv->table, DIOCRCLRADDRS, NULL, 0, 0, NULL, &ndel, 0)) + { + log(L_ERR "Error flushing PF table %s: %m", priv->pf_tablename); + return 0; + } + + DBG("Flushed %d record(s) from PF table %s\n", ndel, priv->pf_tablename); + + return 1; +} + +static int +pf_put_addr(struct pfr_addr *pf_addr, net *n) +{ + int rt_family = AF_INET; + ip_addr addr; + + memset(pf_addr, 0, sizeof(struct pfr_addr)); + pf_addr->pfra_not = 0; + pf_addr->pfra_net = n->n.pxlen; + switch (rt_family) + { + case AF_INET: + addr = n->n.prefix; + ipa_hton(addr); + pf_addr->pfra_ip4addr.s_addr = addr; + pf_addr->pfra_af = rt_family; + break; + default: + log(L_ERR "Address family %d is not supported by pf, ignoring prefix", rt_family); + return 0; + } + + return 1; +} + +int +pf_fw_add(void *_priv, net *n, char *prefixdata) +{ + struct pf_priv *priv = _priv; + struct pfr_addr pf_addr; + int nadd = 0; + + if (!pf_put_addr(&pf_addr, n)) + { + FW_ERR("Error adding %I/%d to PF table %s", n->n.prefix, n->n.pxlen, priv->pf_tablename); + return 0; + } + + DBG("Adding %I/%d to PF table %s with value %s\n", n->n.prefix, n->n.pxlen, priv->pf_tablename, prefixdata); + if (!pf_do_cmd(&priv->table, DIOCRADDADDRS, &pf_addr, sizeof(pf_addr), 1, &nadd, NULL, 0)) + { + FW_ERR("Error adding %I/%d to PF table %s: %m", n->n.prefix, n->n.pxlen, priv->pf_tablename); + return 0; + } + + return 1; +} + +int +pf_fw_del(void *_priv, net *n) +{ + struct pf_priv *priv = _priv; + struct pfr_addr pf_addr; + int ndel = 0; + + if (!pf_put_addr(&pf_addr, n)) + { + FW_ERR("Error deleting %I/%d from PF table %s", n->n.prefix, n->n.pxlen, priv->pf_tablename); + return 0; + } + + DBG("Deleting %I/%d from PF table %s\n", n->n.prefix, n->n.pxlen, priv->pf_tablename); + if (!pf_do_cmd(&priv->table, DIOCRDELADDRS, &pf_addr, sizeof(pf_addr), 1, NULL, &ndel, 0)) + { + FW_ERR("Error deleting %I/%d from PF table %s: %m", n->n.prefix, n->n.pxlen, priv->pf_tablename); + return 0; + } + + return 1; +} + +struct firewall_control fw_pf = { + fwtype: FWTYPE_PF, + description: "PF", + fw_init: pf_fw_init, + fw_shutdown: pf_fw_shutdown, + fw_flush: pf_fw_flush, + fw_add: pf_fw_add, + fw_del: pf_fw_del, +}; +#endif + + +#endif + -- 1.7.3.2 --- configure.orig 2012-08-07 13:28:04.000000000 +0400 +++ configure 2012-08-15 15:54:05.000000000 +0400 @@ -2355,11 +2355,11 @@ if test "$enable_ipv6" = yes ; then ip=ipv6 SUFFIX=6 - all_protocols=bgp,ospf,pipe,radv,rip,static + all_protocols=bgp,ospf,pipe,radv,rip,static,firewall else ip=ipv4 SUFFIX="" - all_protocols=bgp,ospf,pipe,rip,static + all_protocols=bgp,ospf,pipe,rip,static,firewall fi if test "$given_suffix" = yes ; then @@ -4361,6 +4361,8 @@ ipv6:freebsd*) sysdesc=bsd-v6 ;; ipv4:freebsd*) sysdesc=bsd + $as_echo "#define CONFIG_FIREWALL_IPFW 1" >>confdefs.h + $as_echo "#define CONFIG_FIREWALL_PF 1" >>confdefs.h ;; ipv6:dragonfly*) sysdesc=bsd-v6 ;;