From 47a99bfcbe563334be3e171cd2bd34c7956a6d4b Mon Sep 17 00:00:00 2001 From: Fisher Darling Date: Tue, 1 Nov 2022 10:56:35 +0100 Subject: [PATCH] IT FUCKING WORKS --- .../alamesh/bird_example_conf/ogr/bird.conf | 136 ++++++ .../bird_example_conf/ogr/peers/tr.conf | 3 + .../bird_example_conf/template/bird.conf | 136 ++++++ .../template/peers/example.conf | 3 + .../alamesh/bird_example_conf/tr/bird.conf | 136 ++++++ .../bird_example_conf/tr/peers/ogr.conf | 3 + projects/alamesh/setting_up_bird.md | 396 +++++++++++++----- 7 files changed, 704 insertions(+), 109 deletions(-) create mode 100644 projects/alamesh/bird_example_conf/ogr/bird.conf create mode 100644 projects/alamesh/bird_example_conf/ogr/peers/tr.conf create mode 100644 projects/alamesh/bird_example_conf/template/bird.conf create mode 100644 projects/alamesh/bird_example_conf/template/peers/example.conf create mode 100644 projects/alamesh/bird_example_conf/tr/bird.conf create mode 100644 projects/alamesh/bird_example_conf/tr/peers/ogr.conf diff --git a/projects/alamesh/bird_example_conf/ogr/bird.conf b/projects/alamesh/bird_example_conf/ogr/bird.conf new file mode 100644 index 0000000..d1fef72 --- /dev/null +++ b/projects/alamesh/bird_example_conf/ogr/bird.conf @@ -0,0 +1,136 @@ +# ==== CONSTANTS ==== + +define OWNAS = 550001; # your autonomous system number + +# the first non-zero IPv4 you control. Since we're only using +# IPv6. Use the first non-zero 32 bits you control. E.g., if +# you control 255::/16, use 2.85.0.1 (255 is two hex bytes, +# 0x02, and 0x55 which is 2.85 in a v4 addr). +define OWNIP = 2.0.0.1; + +# the router's actual IPv6 addr that it can be reached by. +define OWNIPv6 = 200::1; + +# the subnet you control +define OWNNETv6 = 200::/16; + +# set of all addrs you control. +define OWNNETSETv6 = [200::/16+]; + +# =================== + +router id OWNIP; + +# "everything" is a protocol in bird. The `device` protocol is not really +# a protocol, it just instructs bird to ask the kernel for information +# on devices (interfaces). +protocol device { + # scan devices every 10 seconds. + scan time 10; +} + +# ==== UTILITY FUNCTIONS ==== + +function is_self_net() { + return net ~ OWNNETSETv6; +} + +function is_valid_network() { + return net ~ [ + 0200::/7+ + ]; +} + +# Tell bird how to interact with the kernel (modify routes): +# +# Again, not really a protocol but ¯\_(ツ)_/¯ +protocol kernel { + # scan the routing table every 20 seconds (update bird state). + scan time 20; + + # configure ipv6 + ipv6 { + # Don't import any routes from the kernel, let bird figure out + # what routes to add or change. `none` is a "filter" that discards + # routes that are given to it. The kernel gives bird routes and we + # want bird to ignore them. kernel -> bird. + import none; + + # We write an inline filter that describes what routes to give the + # kernel from bird. bird -> kernel. + export filter { + # if the source of this route is static configuration, then we + # don't want to give it to the kernel. (only want dynamic routes). + # I don't know why this is important? Is that right? + if source = RTS_STATIC then reject; + # set the `krt_prefsrc` attribute for this route. + # see comment above above the kernel block. + krt_prefsrc = OWNIPv6; + # accept this route (don't filter it out). + accept; + }; + }; +} + +# Static protocol lets you define static routes that do not change. +protocol static { + # reject any routes in our subnet (I think?) + route OWNNETv6 reject; + + ipv6 { + # tell bird about everything. static -> bird. + import all; + # bird can't configure static routes (default)?. + # bird -> static. + export none; + }; +} + +# Create a template for the `bgp` protocol. This is where the real +# magic happens. We use a template since every peer will essentially +# have the same BGP configuration. The template name is `alapeers`. +# +# Each peer gets its own template nad file under `peers6/*``. +# +# We're using BGP in "exterior" or `eBGP` mode. This means we're using +# the protocol to define routes between Autonomous Systems, not really +# between individual IP addrs. +# +# Each instance of the `bgp` protocol corresponds with one neighboring +# router, or in our case, a peer. +template bgp alapeers { + # our `as` number is the OWNAS constant. This is defined in the local + # defs file that comes later. + local as OWNAS; + # compare path lengths to determine which route is the best one. + path metric 1; + + ipv6 { + # only accept routes from peers that follow this inline filter. + # bgp -> bird. + import filter { + # Accept the route if its a valid network and is not our + # own network. (fns defined in local defs file). + if is_valid_network() && !is_self_net() then { + accept; + } + reject; + }; + # only send routes that follow this inline filter. + # bird -> bgp (other peers). + export filter { + # Only send if it's a valid netowrk and the route comes from + # static configuration or from BGP. + if is_valid_network() && source ~ [RTS_STATIC, RTS_BGP] then { + accept; + } + reject; + }; + # Only allow for 1000 total routes to be imported. Once we hit + # 1000, block further routes. + import limit 1000 action block; + }; +} + +# Include all of our peers! +include "peers/*"; diff --git a/projects/alamesh/bird_example_conf/ogr/peers/tr.conf b/projects/alamesh/bird_example_conf/ogr/peers/tr.conf new file mode 100644 index 0000000..e41319c --- /dev/null +++ b/projects/alamesh/bird_example_conf/ogr/peers/tr.conf @@ -0,0 +1,3 @@ +protocol bgp test_router_peer from alapeers { + neighbor 255::1 as 550002; # as == autonomous system +} diff --git a/projects/alamesh/bird_example_conf/template/bird.conf b/projects/alamesh/bird_example_conf/template/bird.conf new file mode 100644 index 0000000..713845b --- /dev/null +++ b/projects/alamesh/bird_example_conf/template/bird.conf @@ -0,0 +1,136 @@ +# ==== CONSTANTS ==== + +define OWNAS = ; # your autonomous system number + +# the first non-zero IPv4 you control. Since we're only using +# IPv6. Use the first non-zero 32 bits you control. E.g., if +# you control 255::/16, use 2.85.0.1 (255 is two hex bytes, +# 0x02, and 0x55 which is 2.85 in a v4 addr). +define OWNIP = ; + +# the router's actual IPv6 addr that it can be reached by. +define OWNIPv6 = ; + +# the subnet you control +define OWNNETv6 = ; + +# set of all addrs you control. +define OWNNETSETv6 = [+]; + +# =================== + +router id OWNIP; + +# "everything" is a protocol in bird. The `device` protocol is not really +# a protocol, it just instructs bird to ask the kernel for information +# on devices (interfaces). +protocol device { + # scan devices every 10 seconds. + scan time 10; +} + +# ==== UTILITY FUNCTIONS ==== + +function is_self_net() { + return net ~ OWNNETSETv6; +} + +function is_valid_network() { + return net ~ [ + 0200::/7+ + ]; +} + +# Tell bird how to interact with the kernel (modify routes): +# +# Again, not really a protocol but ¯\_(ツ)_/¯ +protocol kernel { + # scan the routing table every 20 seconds (update bird state). + scan time 20; + + # configure ipv6 + ipv6 { + # Don't import any routes from the kernel, let bird figure out + # what routes to add or change. `none` is a "filter" that discards + # routes that are given to it. The kernel gives bird routes and we + # want bird to ignore them. kernel -> bird. + import none; + + # We write an inline filter that describes what routes to give the + # kernel from bird. bird -> kernel. + export filter { + # if the source of this route is static configuration, then we + # don't want to give it to the kernel. (only want dynamic routes). + # I don't know why this is important? Is that right? + if source = RTS_STATIC then reject; + # set the `krt_prefsrc` attribute for this route. + # see comment above above the kernel block. + krt_prefsrc = OWNIPv6; + # accept this route (don't filter it out). + accept; + }; + }; +} + +# Static protocol lets you define static routes that do not change. +protocol static { + # reject any routes in our subnet (I think?) + route OWNNETv6 reject; + + ipv6 { + # tell bird about everything. static -> bird. + import all; + # bird can't configure static routes (default)?. + # bird -> static. + export none; + }; +} + +# Create a template for the `bgp` protocol. This is where the real +# magic happens. We use a template since every peer will essentially +# have the same BGP configuration. The template name is `alapeers`. +# +# Each peer gets its own template nad file under `peers6/*``. +# +# We're using BGP in "exterior" or `eBGP` mode. This means we're using +# the protocol to define routes between Autonomous Systems, not really +# between individual IP addrs. +# +# Each instance of the `bgp` protocol corresponds with one neighboring +# router, or in our case, a peer. +template bgp alapeers { + # our `as` number is the OWNAS constant. This is defined in the local + # defs file that comes later. + local as OWNAS; + # compare path lengths to determine which route is the best one. + path metric 1; + + ipv6 { + # only accept routes from peers that follow this inline filter. + # bgp -> bird. + import filter { + # Accept the route if its a valid network and is not our + # own network. (fns defined in local defs file). + if is_valid_network() && !is_self_net() then { + accept; + } + reject; + }; + # only send routes that follow this inline filter. + # bird -> bgp (other peers). + export filter { + # Only send if it's a valid netowrk and the route comes from + # static configuration or from BGP. + if is_valid_network() && source ~ [RTS_STATIC, RTS_BGP] then { + accept; + } + reject; + }; + # Only allow for 1000 total routes to be imported. Once we hit + # 1000, block further routes. + import limit 1000 action block; + }; +} + +# Include all of our peers! +include "peers/*"; diff --git a/projects/alamesh/bird_example_conf/template/peers/example.conf b/projects/alamesh/bird_example_conf/template/peers/example.conf new file mode 100644 index 0000000..4ef8f1f --- /dev/null +++ b/projects/alamesh/bird_example_conf/template/peers/example.conf @@ -0,0 +1,3 @@ +protocol bgp from alapeers { + neighbor as ; # as == autonomous system +} diff --git a/projects/alamesh/bird_example_conf/tr/bird.conf b/projects/alamesh/bird_example_conf/tr/bird.conf new file mode 100644 index 0000000..1b3ec3d --- /dev/null +++ b/projects/alamesh/bird_example_conf/tr/bird.conf @@ -0,0 +1,136 @@ +# ==== CONSTANTS ==== + +define OWNAS = 550002; # your autonomous system number + +# the first non-zero IPv4 you control. Since we're only using +# IPv6. Use the first non-zero 32 bits you control. E.g., if +# you control 255::/16, use 2.85.0.1 (255 is two hex bytes, +# 0x02, and 0x55 which is 2.85 in a v4 addr). +define OWNIP = 2.85.0.1; + +# the router's actual IPv6 addr that it can be reached by. +define OWNIPv6 = 255::1; + +# the subnet you control +define OWNNETv6 = 255::/16; + +# set of all addrs you control. +define OWNNETSETv6 = [255::/16+]; + +# =================== + +router id OWNIP; + +# "everything" is a protocol in bird. The `device` protocol is not really +# a protocol, it just instructs bird to ask the kernel for information +# on devices (interfaces). +protocol device { + # scan devices every 10 seconds. + scan time 10; +} + +# ==== UTILITY FUNCTIONS ==== + +function is_self_net() { + return net ~ OWNNETSETv6; +} + +function is_valid_network() { + return net ~ [ + 0200::/7+ + ]; +} + +# Tell bird how to interact with the kernel (modify routes): +# +# Again, not really a protocol but ¯\_(ツ)_/¯ +protocol kernel { + # scan the routing table every 20 seconds (update bird state). + scan time 20; + + # configure ipv6 + ipv6 { + # Don't import any routes from the kernel, let bird figure out + # what routes to add or change. `none` is a "filter" that discards + # routes that are given to it. The kernel gives bird routes and we + # want bird to ignore them. kernel -> bird. + import none; + + # We write an inline filter that describes what routes to give the + # kernel from bird. bird -> kernel. + export filter { + # if the source of this route is static configuration, then we + # don't want to give it to the kernel. (only want dynamic routes). + # I don't know why this is important? Is that right? + if source = RTS_STATIC then reject; + # set the `krt_prefsrc` attribute for this route. + # see comment above above the kernel block. + krt_prefsrc = OWNIPv6; + # accept this route (don't filter it out). + accept; + }; + }; +} + +# Static protocol lets you define static routes that do not change. +protocol static { + # reject any routes in our subnet (I think?) + route OWNNETv6 reject; + + ipv6 { + # tell bird about everything. static -> bird. + import all; + # bird can't configure static routes (default)?. + # bird -> static. + export none; + }; +} + +# Create a template for the `bgp` protocol. This is where the real +# magic happens. We use a template since every peer will essentially +# have the same BGP configuration. The template name is `alapeers`. +# +# Each peer gets its own template nad file under `peers6/*``. +# +# We're using BGP in "exterior" or `eBGP` mode. This means we're using +# the protocol to define routes between Autonomous Systems, not really +# between individual IP addrs. +# +# Each instance of the `bgp` protocol corresponds with one neighboring +# router, or in our case, a peer. +template bgp alapeers { + # our `as` number is the OWNAS constant. This is defined in the local + # defs file that comes later. + local as OWNAS; + # compare path lengths to determine which route is the best one. + path metric 1; + + ipv6 { + # only accept routes from peers that follow this inline filter. + # bgp -> bird. + import filter { + # Accept the route if its a valid network and is not our + # own network. (fns defined in local defs file). + if is_valid_network() && !is_self_net() then { + accept; + } + reject; + }; + # only send routes that follow this inline filter. + # bird -> bgp (other peers). + export filter { + # Only send if it's a valid netowrk and the route comes from + # static configuration or from BGP. + if is_valid_network() && source ~ [RTS_STATIC, RTS_BGP] then { + accept; + } + reject; + }; + # Only allow for 1000 total routes to be imported. Once we hit + # 1000, block further routes. + import limit 1000 action block; + }; +} + +# Include all of our peers! +include "peers/*"; diff --git a/projects/alamesh/bird_example_conf/tr/peers/ogr.conf b/projects/alamesh/bird_example_conf/tr/peers/ogr.conf new file mode 100644 index 0000000..2681e77 --- /dev/null +++ b/projects/alamesh/bird_example_conf/tr/peers/ogr.conf @@ -0,0 +1,3 @@ +protocol bgp og_router_peer from alapeers { + neighbor 200::1 as 550001; # as == autonomous system +} diff --git a/projects/alamesh/setting_up_bird.md b/projects/alamesh/setting_up_bird.md index 5910000..298e873 100644 --- a/projects/alamesh/setting_up_bird.md +++ b/projects/alamesh/setting_up_bird.md @@ -10,7 +10,7 @@ with another router will come in an edit or separate post. # My Network I'm not trying to to any sort of dynamic routing yet, but here's what I have working right now. My current network is -the entire `0200::/7` address space (all addresses prefixed with `0x02` and `0x0[01]`). +the entire `0200::/7` address space (all addresses prefixed with `0x0(2|3)`). ``` ┌──────────┐ wg tunnel @@ -88,6 +88,29 @@ in bird. Protocols describe how to interact with the kernel, BGP, static route, ## bird.conf ``` +# ==== CONSTANTS ==== + +define OWNAS = ; # your autonomous system number + +# the first non-zero IPv4 you control. Since we're only using +# IPv6. Use the first non-zero 32 bits you control. E.g., if +# you control 255::/16, use 2.85.0.1 (255 is two hex bytes, +# 0x02, and 0x55 which is 2.85 in a v4 addr). +define OWNIP = ; + +# the router's actual IPv6 addr that it can be reached by. +define OWNIPv6 = ; + +# the subnet you control +define OWNNETv6 = ; + +# set of all addrs you control. +define OWNNETSETv6 = [+]; + +# =================== + +router id OWNIP; + # "everything" is a protocol in bird. The `device` protocol is not really # a protocol, it just instructs bird to ask the kernel for information # on devices (interfaces). @@ -96,61 +119,61 @@ protocol device { scan time 10; } -# Include our local configuration. -# -# We define our own AS and subnet in here along with some -# helper functions for determining if a route is in our -# own network. We'll cover this short file later. -include "/etc/bird/local6.conf +# ==== UTILITY FUNCTIONS ==== + +function is_self_net() { + return net ~ OWNNETSETv6; +} + +function is_valid_network() { + return net ~ [ + 0200::/7+ + ]; +} # Tell bird how to interact with the kernel (modify routes): # # Again, not really a protocol but ¯\_(ツ)_/¯ - -# Comment from dn42's guide: -/* - krt_prefsrc defines the source address for outgoing connections. - On Linux, this causes the "src" attribute of a route to be set. - - Without this option outgoing connections would use the peering IP which - would cause packet loss if some peering disconnects but the interface - is still available. (The route would still exist and thus route through - the TUN/TAP interface but the VPN daemon would simply drop the packet.) -*/ protocol kernel { # scan the routing table every 20 seconds (update bird state). scan time 20; - - # Don't import any routes from the kernel, let bird figure out - # what routes to add or change. `none` is a "filter" that discards - # routes that are given to it. The kernel gives bird routes and we - # want bird to ignore them. kernel -> bird. - import none; - - # We write an inline filter that describes what routes to give the - # kernel from bird. bird -> kernel. - export filter { - # if the source of this route is static configuration, then we - # don't want to give it to the kernel. (only want dynamic routes). - # I don't know why this is important? Is that right? - if source = RTS_STATIC then reject; - # set the `krt_prefsrc` attribute for this route. - # see comment above above the kernel block. - krt_prefsrc = OWNIP; - # accept this route (don't filter it out). - accept; + + # configure ipv6 + ipv6 { + # Don't import any routes from the kernel, let bird figure out + # what routes to add or change. `none` is a "filter" that discards + # routes that are given to it. The kernel gives bird routes and we + # want bird to ignore them. kernel -> bird. + import none; + + # We write an inline filter that describes what routes to give the + # kernel from bird. bird -> kernel. + export filter { + # if the source of this route is static configuration, then we + # don't want to give it to the kernel. (only want dynamic routes). + # I don't know why this is important? Is that right? + if source = RTS_STATIC then reject; + # set the `krt_prefsrc` attribute for this route. + # see comment above above the kernel block. + krt_prefsrc = OWNIPv6; + # accept this route (don't filter it out). + accept; + }; }; } # Static protocol lets you define static routes that do not change. protocol static { # reject any routes in our subnet (I think?) - route reject; - # tell bird about everything. static -> bird. - import all; - # bird can't configure static routes (default)?. - # bird -> static. - export none; + route OWNNETv6 reject; + + ipv6 { + # tell bird about everything. static -> bird. + import all; + # bird can't configure static routes (default)?. + # bird -> static. + export none; + }; } # Create a template for the `bgp` protocol. This is where the real @@ -171,77 +194,39 @@ template bgp alapeers { local as OWNAS; # compare path lengths to determine which route is the best one. path metric 1; - - # remember rejected routes for later debugging. - import keep filtered; - - # only accept routes from peers that follow this inline filter. - # bgp -> bird. - import filter { - # Accept the route if its a valid network and is not our - # own network. (fns defined in local defs file). - if is_valid_network() && !is_self_net() then { - accept; - } - reject; + + ipv6 { + # only accept routes from peers that follow this inline filter. + # bgp -> bird. + import filter { + # Accept the route if its a valid network and is not our + # own network. (fns defined in local defs file). + if is_valid_network() && !is_self_net() then { + accept; + } + reject; + }; + # only send routes that follow this inline filter. + # bird -> bgp (other peers). + export filter { + # Only send if it's a valid netowrk and the route comes from + # static configuration or from BGP. + if is_valid_network() && source ~ [RTS_STATIC, RTS_BGP] then { + accept; + } + reject; + }; + # Only allow for 1000 total routes to be imported. Once we hit + # 1000, block further routes. + import limit 1000 action block; }; - # only send routes that follow this inline filter. - # bird -> bgp (other peers). - export filter { - # Only send if it's a valid netowrk and the route comes from - # static configuration or from BGP. - if is_valid_network() && source ~ [RTS_STATIC, RTS_BGP] then { - accept; - } - reject; - }; - - # Only allow for 1000 total routes to be imported. Once we hit - # 1000, block further routes. - import limit 1000 action block; } # Include all of our peers! -include "/etc/bird/peers6/*"; +include "peers/*"; ``` -Whew, that was a rather larger file but that's pretty much it. Now for our local configuration and what a peer looks -like. - -## local6.conf - -``` -# Our globally unique identifier. Most people in dn42 us their internal router's ip. -# I wonder if a UUID or something would work here? -router id ; - -# Define our own Autonomous System Number here: -define OWNAS = ; - -# Define the router's ip: -define OWNIP = ; - -# Now for some helper functions (filters) that we use in the config above: - -# Returns if the `net` special variable (what the route is actually -# talking about, could be prefix. generally some kind of address), -# is in our own subnet. The `+` after the subnet is shorthand for -# "every possible address in this subnet". -# -# `a ~ b` means "a is in b". -function is_self_net() { - return net ~ [+]; -} - -# We use this function to limit our routes to those that are in the alanet. -function is_valid_network() { - return net ~ [ - 0200::/7+ # All address that start with 0200 are in our network. - ] -} -``` - -That's it for the local configuration! Define some constants and two simple helper functions. +Whew, that was a rather larger file but that's pretty much it. Now to configure a peer. ## peers/*.conf @@ -270,4 +255,197 @@ something up. I need to determine a fake AS number, subnets, etc, and then I'll report back if it works or not. To test the bird configuration, I plan to connect lykos to a different router running on a different subnet, and then ssh into hyperion -from lykos. The routes should "just work" (right lol). \ No newline at end of file +from lykos. The routes should "just work" (right lol). + + +# (edit) Testing Bird with Two Routers + +I have two DO droplets that will run bird. Here's how I'm setting up the network. + +OG Router (OGR): +- `AS`: AS550001 +- `router id`: 2.0.0.1 +- `GATEWAY_IP`: `0200::1` +- `SUBNET`: `0200::/16` +- Internal WG Interface: ohea0 + +Test Router (TR): +- `AS`: AS550002 +- `router id`: 2.85.0.1 +- `GATEWAY_IP`: `0255::1` +- `SUBNET`: `0255::/16` +- Internal WG Interface: alanet0 + +I'm keeping hyperion connected to OGR with address `0200::3`. Lykos will connect to TR with address `0255::2`. I've +setup wireguard (wg) on my two clients, hyperion and lykos, to allow all IPs from `0200::/7`. + +Things started getting a little hairy here. `wg-quick` automatically sets up the routing table which interferes with +bird, so we need to disable it with `Table = off` in our WG configuration. I also enabled `PersistentKeepalive` with +my two routers in order to confirm that a tunnel could actually be created. Since I disabled the wg routing table, I +can't seem to ping one router from the other. I believe this is because there is nothing telling the kernel to route +arbitrary `200::/7` packets to the wg tunnel and from the wg tunnel to the router I'm trying to ping. I'm guessing bird +will set this up for me when I add a peer. + +## Adding bird to each router + +I've put the configuration for both routers under the bird_conf dir. `ogr` for the OG Router, `tr` for the test +router, and `template` for the template files above. + +Updating a server conf: +``` +rsync -a ogr/* router:.bird +``` + +### First Snag, the Router ID + +The `router id` in `local.conf` needs to be an IPv4 address (ugh). I'm just going to use my router's public ipv4 addr +and call it good. + +### Second Snag, Syntax + +Syntax errors everywhere. + +### Third Snag, wrong bird version + +FML. The guide from dn42 was for bird 1.6.3, and I'm running bird 2.0.10. dn42 has a [bird2 guide](https://dn42.eu/howto/Bird2) +which I'm using to modify the configuration that I wrote about above. This has led to more syntax errors... + +Some of the errors have been rather helpful though! +``` +bird: bird.conf:15:28 Invalid IPv6 prefix 200::1/16, maybe you wanted 200::/16 +``` + +## Running bird + +After fixing those errors and changing the conf file, here's the command I'm using to run bird: +``` +bird -d -c bird.conf +``` +`-d` for debug messages and for running in the foreground and `-c` to point to my local config file, `.bird/bird.conf`. + +Apparently ubuntu has a `bird2` package that's bird version `2.0.9-3`. I'll attempt to use that for the test-router. + +I have bird running on both routers now. Now the _real_ debugging begins. + +# Further wg configuration + +After reading [dn42's guide on wireguard](https://dn42.eu/howto/wireguard) I believe we need tell the interface that +it's point-to-point and split up the config. + +Here's my wireguard setup for ogr: + +I now have two wireguard config files, `ohea0.conf` and `peer-tr.conf`. `ohea0.conf` has all of my configuration for my +local devices and lets lykos ssh into hyperion through ogr. It's a standard wg configuration. The key here is that **I'm +listening on port 50005**. `peer-tr.conf` is an interface just for peering with the `test-router`. I expect that wg +configuration to be copy-pasted for each peer, albeit with modified `ListenPort`s. + +Internal Network: `ohea0.conf` +``` +[Interface] +PrivateKey = (redacted) +Address = 200::1/16 +ListenPort = 50005 + +[Peer] +PublicKey = ZKR6n8/IersOc1SKoUyU6Z3/q/jPeZs5ljf4hg04pA0= +AllowedIPs = 0200::3/128 +``` + +BGP Peer: `peer-tr.conf` +``` +[Interface] +PrivateKey = +# Different listen port for peers! +ListenPort = 50004 +# Make this link a point-to-point connection. +# Note ogr's ip 200::1 and the peer's (tr's) ip 255::1 +PostUp = /sbin/ip addr add dev %i 200::1/128 peer 255::1/128 +# Don't modify any routes +Table = off + +[Peer] +PublicKey = C6RPH/RMqZ9u0ot6XN8ZcS+vTtU2zo9ZD7+wCfPzHxg= +AllowedIPs = 0200::/7 +Endpoint = 46.101.144.104:50004 +PersistentKeepalive = 25 +``` + +The config for `tr` is essentially the same, just flipping the ips and keys. + +`ogr` can now ping `tr` and we're now split on multiple interfaces. + +# Debugging BGP + +After making the peer wg config point-to-point, ogr's and tr's birds starting speaking BGP with eachother. I used the +bird client `birdc` to see if anything changed. `birdc` connects to the currently running bird process over the control +socket created when bird starts. + +Run `show protocols` to get the list of configured protocols (blocks in the config file). Here's what ogr's protocols +look like: + +``` +bird> show protocols +Name Proto Table State Since Info +device1 Device --- up 09:10:13.122 +kernel1 Kernel master6 up 09:10:13.122 +static1 Static master6 up 09:10:13.122 +peer_test_router BGP --- up 09:10:22.257 Established +``` + +And `show protocols peer_test_router` gives much more info on BGP that's running. I saw in that output that some routes +were added/seen by bird. + +Here's `show route stats`: + +``` +bird> show route stats +Table master4: +0 of 0 routes for 0 networks in table master4 + +Table master6: +200::/16 unreachable [static1 09:10:13.122] * (200) +255::/16 unicast [peer_test_router 09:10:23.124] * (100) [AS550002i] + via 255::1 on peer-tr +2 of 2 routes for 2 networks in table master6 + +Total: 2 of 2 routes for 2 networks in 2 tables +``` + +Seeing `255::/16` in there is promising, since that's the subnet that the `test-router` controls (comes from +AS550002). + +Let's try it out! + +# IT FUCKING WORKS + +I ssh'ed into `hyperion` FROM `lykos`! This is pretty fuckin cool. I feel like some sort of internet god. + +Here's my final topology: + +``` +┌───────────┐ ┌───────────┐ +│ ogr │peer-tr │ tr │ +│ 200::1/16 ◄────────────────► 255::1/16 │ +│ AS55001 │ peer-ogr│ AS55002 │ +└────▲──────┘ └────▲──────┘ + │ │ + │ohea0 alanet0│ + │ │ + │ │ +┌────▼─────┐ ┌────▼───┐ +│ hyperion │ │ lykos │ +│ 200::3 │ │ 255::2 │ +└──────────┘ └────────┘ +``` + +So in order to ssh from lykos, tr needed to know that it could send `200::/16` packets to ogr. Remember that the wg link +from tr <-> ogr is only point-to-point, there was no concept of a subnet. That means routing info for ogr must have been +set by bird in tr's routing table, which allowed the IP/TCP packets to be forwarded to hyperion. + +# Conclusion + +That was a grind. I think like 99% of it can be automated with a nice tool and config file, at least all of the bird +configuration. Auto configuring WG is also pretty doable. + +We still need to test this with multiple peers using an actual "network", but that's not too bad. +