Skip to content

hack3ric/flow

Repository files navigation

Flow

Flow enables BGP Flow Specification (flowspec) on Linux software routers/firewalls. It acts as a sink that receives routes from another BGP speaker and transforms flowspecs into nftables rules and kernel routing tables via rtnetlink(7).

It:

  • executes BGP flowspec on Linux, using nftables and rtnetlink;
  • enables what previously can only be done on commercial routers or bulky routing software on lightweight Linux systems.

It doesn't:

  • work as a full-blown BGP client; you will need another BGP implementation (likely running on the same node) like BIRD, OpenBGPD or GoBGP to peer with others;
  • allow multiple BGP sessions, only one-on-one;
  • initiate BGP session actively;
  • currently support VRF and VPN routes.

Flow has yet to be tested thoroughly and not suitable for production for now. Use and test at your own risk!

Implemented RFCs/Drafts

Usage

Run Flow with default settings that listens to wildcard with port 179, local AS 65000, router ID 127.0.0.1, and no restriction to the other BGP speaker:

# flow run

Allow only local AS (IBGP) and IPv6 loopback incoming IP for peer, and change listening port to 1179:

# flow run -b [::]:1179 -l 65001 -r 65001 -a ::1/128

The configuration options can be stored in a file and passed directly to Flow using the -f option:

# flow run -f flow.conf
# flow.conf

# Each line is exactly one argument without `--`, and spaces are preserved as-is.
# Empty lines and lines starting with '#' are ignored.

bind=[::1]:1179
local-as=65001
remote-as=65001

# The prefix length can be omitted if it contains only one IP
allowed-ips=::1

Configure the remote BGP speaker so it connects and sends flowspecs to Flow. You may need to enable multihop if they are connecting through loopback. For example in BIRD:

flow4 table myflow4;
flow6 table myflow6;

protocol bgp flow {
  local port 1180 as 65001;
  neighbor ::1 port 1179 as 65001;
  multihop;

  flow4 { table myflow4; import none; export all; };
  flow6 { table myflow6; import none; export all; };
}

Show information of currently running Flow instance:

# flow show

Building

Just use your general Cargo workflow:

$ cargo build
$ cargo run
$ cargo xtask sudo run -- run  # short for:
$ cargo --config "target.'cfg(target_os = \"<your OS>\")'.runner = 'sudo -E'" run -- run

To generate manpages and shell autocompletions into target/assets directory, run:

$ cargo xtask gen

Running Tests

Intergration tests involve exchanging information with BGP daemons and modifying kernel network interface. For example, on Linux, install BIRD (>2.x), ExaBGP (>4.x) and use unshare(1) to run the full sets of tests:

$ cargo xtask unshare test  # shortcut for:
$ cargo --config "target.'cfg(target_os = \"linux\")'.runner = 'unshare -rn'" test

If unshare or similar unprivileged isolation methods are unavailable, be careful when running tests with root, since modifications to host network may not be completely reverted in test code:

$ cargo xtask sudo test  # shortcut for:
$ cargo --config "target.'cfg(target_os = \"<your OS>\")'.runner = 'sudo -E'" test

Or, skip integration tests and run only unit tests:

$ cargo test -- --skip integration_tests

BIRD and ExaBGP path can be specified via the FLOW_BIRD_PATH environment variable:

$ FLOW_BIRD_PATH=/path/to/my/bird FLOW_EXABGP_PATH=/path/to/my/exabgp cargo <...options> test

Future Work

  • Programmatic handling: custom traffic filter actions and route handling (not limited to flowspecs)
  • Validation procedure: currently this can be done from the connecting BGP speaker, but for the sake of completeness and also future programmability it should also be done here
  • VPN routes and VRF redirection: does not have many knowledge right now, but certainly doable
  • *BSD support: provide an alternative to Linux; first FreeBSD (that uses pf and reuse existing rtnetlink code), and then OpenBSD (route(4))

License

Flow is licensed under the BSD 2-Clause License. See LICENSE file for detail.