26a9228f52e4bb973674f2e69ca64899f0ab10fa
howto/OpenBGPD.md
... | ... | @@ -1,135 +1,220 @@ |
1 | 1 | This guide describes a simple configuration for [OpenBGPD](https://openbgpd.org) running on [OpenBSD](https://openbsd.org). |
2 | 2 | The [portable version](https://openbgpd.org/ftp.html) should run with little to no configuration changes on other operating systems as well. |
3 | 3 | |
4 | -# Setup |
|
5 | -Only IPv6 is used for the sake of simplicity. |
|
6 | -Neighbors use ULA addresses (/127 transfer net) assigned from one of the peer's allocation. |
|
4 | +Other than the |
|
5 | +[`bgpd.conf(5)`](https://man.openbsd.org/bgpd.conf.5) and |
|
6 | +[`bgpd(8)`](http://man.openbsd.org/bgpd.8) man pages and the |
|
7 | +OpenBSD |
|
8 | +[`/etc/examples/bgpd.conf`](http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/etc/examples/bgpd.conf?rev=HEAD&content-type=text/plain&only_with_tag=MAIN), |
|
9 | +you might also find useful reference or ideas in the |
|
10 | +[Bird2](/howto/Bird2) page (even if you don't use Bird), as |
|
11 | +it likely presents the most widespread dn42 router setup. |
|
12 | + |
|
13 | +# Example configuration |
|
14 | +When copying from the below configuration, be sure to at |
|
15 | +least replace the various `<PLACEHOLDER>`s with your own |
|
16 | +numbers. |
|
17 | + |
|
18 | +Concrete configuration examples can also be found elsewhere, |
|
19 | +e.g.: |
|
20 | + |
|
21 | +[https://smrk.net/text/openbsd-dn42-setup.txt](https://smrk.net/text/openbsd-dn42-setup.txt) |
|
22 | + |
|
23 | +[https://kaizo.org/2024/01/03/openbsd-bgpd/](https://kaizo.org/2024/01/03/openbsd-bgpd/) |
|
24 | + |
|
25 | +Given OpenBGPD's limited support for multiprotocol sessions |
|
26 | +(no extended next hop (RFC8950)) and |
|
27 | +[some](https://marc.info/?l=openbgpd-users&m=159983144408845&w=2) |
|
28 | +[issues](https://marc.info/?l=openbgpd-users&m=165605427017298&w=2) |
|
29 | +with IPv6 link-local nexthops, we configure separate IPv4 |
|
30 | +and IPv6 sessions for each peer, and for IPv6 we adjust |
|
31 | +nexthop to a "global" address (i.e., one from our dn42 IPv6 |
|
32 | +allocation) assigned to each peering (Wireguard) interface |
|
33 | +(each interface gets its own). |
|
34 | + |
|
35 | +To avoid burning a dn42 IPv4 address for each peering, we'll |
|
36 | +put the router's dn42 IPv4 address on the loopback interface |
|
37 | +and peer using an RFC1918 subnet (192.168.42/24) NATed to |
|
38 | +the loopback address (the NAT is only used in case of |
|
39 | +actively opening an IPv4 BGP session, it does not affect |
|
40 | +routing or incoming connections). |
|
41 | + |
|
42 | +## `/etc/hostname.lo0` |
|
7 | 43 | |
8 | -The goal is to have a small, yet complete setup for all peers with ROA validation and other safety measures in place. |
|
9 | - |
|
10 | -# Configuration |
|
11 | -[`/etc/bgpd.conf`](https://man.openbsd.org/bgpd.conf.5) contains all information and may include further (automatically generated) files, as is done in this guide. |
|
12 | - |
|
13 | -As per the manual, configuration is divided into logical sections; [`/etc/examples/bgpd.conf`](http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/etc/examples/bgpd.conf?rev=HEAD&content-type=text/plain&only_with_tag=MAIN) is a complete and commented example which this guide is roughly based on. |
|
14 | - |
|
15 | -By default, [bgpd(8)](http://man.openbsd.org/bgpd.8) listens on all local addresses (on the current default [`routing domain`](http://man.openbsd.org/rdomain.4)), but this guide explicitly listens on the configured transfer ULA only for each peer to better illustrate this setup. |
|
16 | - |
|
17 | -## local host |
|
18 | -Information such as ASN, router ID and allocated networks are required: |
|
19 | 44 | ```conf |
20 | -# macros |
|
21 | -ASN="4242421234" |
|
45 | +alias <YOUR-ROUTER-DN42-IPv4> |
|
46 | +``` |
|
22 | 47 | |
23 | -# global configuration |
|
24 | -AS $ASN |
|
25 | -router-id 1.2.3.4 |
|
48 | +## `/etc/hostname.wg1234` |
|
49 | +(one example; similar for each peer) |
|
26 | 50 | |
27 | -prefix-set mynetworks { |
|
28 | - fd00:12:34::/48 |
|
29 | -} |
|
51 | +```conf |
|
52 | +inet 192.168.42.1/32 |
|
53 | +inet6 fe80::1 64 # this is the address your peer will want to know |
|
54 | +# (and connect to); the following address is only really needed |
|
55 | +# to provide a non-link-local IPv6 address for the nexthop setting; |
|
56 | +# you can pick it "arbitrarily" from your dn42 IPv6 allocation |
|
57 | +inet6 <YOUR-DN42-IPv6-OF-PEER1-INTERFACE> 64 |
|
58 | +group my_dn |
|
59 | +wgport 21234 wgkey <PRIVKEY-BASE64> |
|
60 | +wgpeer <PEER1-PUBKEY-BASE64> \ |
|
61 | + wgdescr "dn42 peer1" \ |
|
62 | + wgaip fe80::/64 wgaip fd00::/8 wgaip 10.0.0.0/8 wgaip 172.20.0.0/14 \ |
|
63 | + wgendpoint <PEER1-HOSTNAME-OR-IP> 24321 |
|
64 | +up |
|
65 | +# add a static IPv4 route to the peer |
|
66 | +!route -nq add <PEER1-IPv4> 192.168.42.1 |
|
30 | 67 | ``` |
31 | 68 | |
32 | -These can be used in subsequent filter rules. |
|
33 | -The local peer's announcements is then defined as follows: |
|
69 | +## `/etc/pf.conf` |
|
70 | +(only the dn42-related snippet) |
|
71 | + |
|
34 | 72 | ```conf |
35 | -# Generate routes for the networks our ASN will originate. |
|
36 | -# The communities (read 'tags') are later used to match on what |
|
37 | -# is announced to EBGP neighbors |
|
38 | -network prefix-set mynetworks set large-community $ASN:1:1 |
|
73 | +pass in quick proto {icmp icmp6} max-pkt-rate 30/3 |
|
74 | +dn42_self = <YOUR-ROUTER-DN42-IPv4> |
|
75 | +table <dn42etc> const {172.20/14 172.31/16 10/8 fd00::/8 fe80::/64} |
|
76 | +table <dn42peers> const {<PEER1-IPv4> fe80::/64} |
|
77 | +pass in quick on egress proto udp to port 21234 |
|
78 | +pass in quick on my_dn proto tcp from <dn42peers> \ |
|
79 | + to {$dn42_self (my_dn)} port bgp |
|
80 | +# block everything (except for ICMP above) destined to the |
|
81 | +# router itself; only dn42 transit and BGP sessions are allowed |
|
82 | +block in log quick on my_dn to {$dn42_self (my_dn)} |
|
83 | +pass out on my_dn from 192.168.42/24 nat-to $dn42_self |
|
84 | +pass on my_dn from <dn42etc> to <dn42etc> |
|
39 | 85 | ``` |
40 | 86 | |
41 | -## neighbors |
|
42 | -For each neighbor its ASN and transfer ULA is required. |
|
43 | -An optional description is provided such that [bgpctl(8)](http://man.openbsd.org/bgpctl.8) for example can be used with mnemonic names instead of AS numbers: |
|
87 | +## `/etc/bgpd.conf` |
|
44 | 88 | ```conf |
45 | -# peer A, transport over IPSec/GRE |
|
46 | -$A_local="fd00:12:34:A::1" |
|
47 | -$A_remote="fd00:12:34:A::2" |
|
48 | -$A_ASN="4242425678" |
|
89 | +ASN = "<YOUR-AS-NUMBER>" |
|
49 | 90 | |
50 | -listen on $A_local |
|
91 | +AS $ASN |
|
92 | +router-id <YOUR-ROUTER-DN42-IPv4> |
|
51 | 93 | |
52 | -neighbor $A_remote { |
|
53 | - remote-as $A_ASN |
|
54 | - descr "A" |
|
94 | +# list of networks that may be originated by our ASN |
|
95 | +prefix-set mydn42 { |
|
96 | + <YOUR-DN42-IPv4-PREFIX> |
|
97 | + <YOUR-DN42-IPv6-PREFIX> |
|
55 | 98 | } |
56 | -``` |
|
57 | - |
|
58 | -## filter rules |
|
59 | -**bgpd** blocks all BGP __UPDATE__ messages by default. |
|
60 | -The filter rules are evaluated in sequential order, from first to last. |
|
61 | -The last matching allow or deny rule decides what action is taken. |
|
62 | - |
|
63 | -Start off with basic protection and sanity rules: |
|
64 | -```conf |
|
65 | -# deny more-specifics of our own originated prefixes |
|
66 | -deny quick from ebgp prefix-set mynetworks or-longer |
|
67 | 99 | |
68 | -# filter out too long paths, establish more peerings instead |
|
69 | -deny quick from any max-as-len 8 |
|
70 | -``` |
|
100 | +# https://dn42.eu/howto/Bird2#example-configuration |
|
101 | +prefix-set dn42etc { |
|
102 | + 172.20.0.0/14 prefixlen 21 - 29 # dn42 |
|
103 | + 172.20.0.0/24 prefixlen 28 - 32 # dn42 Anycast |
|
104 | + 172.21.0.0/24 prefixlen 28 - 32 # dn42 Anycast |
|
105 | + 172.22.0.0/24 prefixlen 28 - 32 # dn42 Anycast |
|
106 | + 172.23.0.0/24 prefixlen 28 - 32 # dn42 Anycast |
|
107 | + 172.31.0.0/16 or-longer # ChaosVPN |
|
108 | + 10.100.0.0/14 or-longer # ChaosVPN |
|
109 | + 10.127.0.0/16 prefixlen 16 - 32 # neonetwork |
|
110 | + 10.0.0.0/8 prefixlen 15 - 24 # Freifunk.net |
|
111 | + fd00::/8 prefixlen 44 - 64 # dn42 |
|
112 | +} |
|
71 | 113 | |
72 | -`quick` rules are considered the last matching rule, and evaluation of subsequent rules is skipped. |
|
114 | +# https://dn42.burble.com/services/public/#roa-data |
|
115 | +# https://dn42.burble.com/roa/dn42_roa_obgpd_46.conf |
|
116 | +# see the crontab snippet and an update script further below |
|
117 | +include "/var/db/openbgpd/dn42_roa_obgpd_46.conf" |
|
118 | + |
|
119 | +network prefix-set mydn42 set { |
|
120 | + # https://dn42.dev/howto/BGP-communities |
|
121 | + # e.g., for Germany this could read |
|
122 | + # community 64511:41 |
|
123 | + # community 64511:1276 |
|
124 | + community 64511:<READ-THE-LINK-ABOVE> |
|
125 | + community 64511:<READ-THE-LINK-ABOVE> |
|
126 | + large-community $ASN:1:1 |
|
127 | +} |
|
73 | 128 | |
74 | -Allow own announcements: |
|
75 | -```conf |
|
76 | -# Outbound EBGP: only allow self originated networks to ebgp peers |
|
77 | -# Don't leak any routes from upstream or peering sessions. This is done |
|
78 | -# by checking for routes that are tagged with the large-community $ASN:1:1 |
|
79 | -allow to ebgp prefix-set mynetworks large-community $ASN:1:1 |
|
80 | -``` |
|
129 | +listen on <YOUR-ROUTER-DN42-IPv4> |
|
130 | +listen on <PEER1-IPv6-LOCAL> # e.g. fe80::1%wg1234 |
|
131 | + |
|
132 | +group dn42peers { |
|
133 | + # RFC7454 sec. 8 |
|
134 | + # (currently no peer sends more than 800 prefixes for |
|
135 | + # a single address family; increase this if using |
|
136 | + # multi-protocol BGP (or when the network grows)!) |
|
137 | + max-prefix 1000 restart 60 |
|
138 | + neighbor <PEER1-IPv4> { |
|
139 | + descr peer1_4 |
|
140 | + remote-as <PEER1-ASN> |
|
141 | + } |
|
142 | + neighbor <PEER1-IPv6-REMOTE> { # e.g. fe80::2%wg1234 |
|
143 | + descr peer1_6 |
|
144 | + remote-as <PEER1-ASN> |
|
145 | + set nexthop <YOUR-DN42-IPv6-OF-PEER1-INTERFACE> |
|
146 | + } |
|
147 | +} |
|
81 | 148 | |
82 | -Allow all remaining UPDATES based on **O**rigin **V**alidation **S**tates: |
|
83 | -```conf |
|
84 | -# enforce ROA |
|
85 | -allow from ebgp ovs valid |
|
86 | -``` |
|
149 | +# deny EBGP UPDATEs to our own originated prefixes |
|
150 | +deny quick from ebgp prefix-set mydn42 or-longer |
|
151 | +# filter out overlong paths |
|
152 | +deny quick from any max-as-len 10 |
|
87 | 153 | |
88 | -Note how the `ovs` filter requires the `roa-set {...}` to be defined; see the `ROA` section below. |
|
154 | +allow from group dn42peers prefix-set dn42etc ovs valid |
|
155 | +allow to group dn42peers prefix-set dn42etc |
|
89 | 156 | |
90 | -### path attributes |
|
91 | -Besides `allow` and `deny` statements, filter rules can modify UPDATE messages, e.g. |
|
92 | -```conf |
|
93 | -# Scrub normal and large communities relevant to our ASN from EBGP neighbors |
|
94 | -# https://tools.ietf.org/html/rfc7454#section-11 |
|
157 | +# scrub communities relevant to our ASN from EBGP neighbors |
|
158 | +# (RFC7454 sec. 11) |
|
159 | +# match from ebgp set { community delete $ASN:* } |
|
95 | 160 | match from ebgp set { large-community delete $ASN:*:* } |
96 | 161 | |
97 | -# Honor requests to gracefully shutdown BGP sessions |
|
98 | -# https://tools.ietf.org/html/rfc8326 |
|
162 | +# honor requests to gracefully shutdown BGP sessions (RFC8326) |
|
99 | 163 | match from any community GRACEFUL_SHUTDOWN set { localpref 0 } |
100 | 164 | ``` |
101 | 165 | |
102 | -# ROA |
|
166 | +## ROA |
|
103 | 167 | |
104 | -An roa-set can be generated from the registry directly or you can use the following pre-built tables. |
|
168 | +The `roa-set` for route origin validation (`ovs valid` in |
|
169 | +the config above) can be generated from the dn42 registry; |
|
170 | +here we use |
|
171 | +[data](https://dn42.burble.com/services/public/#roa-data) |
|
172 | +conveniently provided by BURBLE-MNT. |
|
105 | 173 | |
106 | -One single `roa-set` may be defined, against which **bgpd** will validate the origin of each prefix; this allows filter rules to use the `ovs` keyword as demonstrated above. |
|
174 | +If using the update script below, don't forget to create the |
|
175 | +`/var/db/openbgpd/` directory first. |
|
107 | 176 | |
108 | -ROA files generated by [dn42regsrv](https://git.dn42.dev/burble/dn42regsrv) are available from burble.dn42: |
|
177 | +### `/root/openbgpd-roa-update.sh` |
|
178 | +```sh |
|
179 | +#!/bin/sh |
|
109 | 180 | |
110 | -|URL| IPv4/IPv6 | |
|
111 | -|---|---| |
|
112 | -| <https://dn42.burble.com/roa/dn42_roa_obgpd_46.conf> | Both | |
|
113 | -| <https://dn42.burble.com/roa/dn42_roa_obgpd_4.conf> | IPv4 Only | |
|
114 | -| <https://dn42.burble.com/roa/dn42_roa_obgpd_6.conf> | IPv6 Only | |
|
115 | - |
|
116 | -`/etc/dn42.roa-set` is the generated set: |
|
117 | -```conf |
|
118 | -roa-set { |
|
119 | - fd00:12:34::/48 source-as 4242421234 |
|
120 | - fd00:ab:cd::/44 maxlen 64 source-as 4242427890 |
|
121 | - ... |
|
181 | +die() { |
|
182 | + >&2 printf '%s: %s\n' "${0##*/}" "$*" |
|
183 | + exit 1 |
|
122 | 184 | } |
185 | + |
|
186 | +# Unfortunately, burble regenerates the ROA files (hourly?) |
|
187 | +# even when nothing changed, so If-Modified-Since doesn't |
|
188 | +# help (similar story for .meta). |
|
189 | + |
|
190 | +metafile=/var/db/openbgpd/registry.meta |
|
191 | +err=$(ftp -o "$metafile" \ |
|
192 | + https://explorer.burble.com/api/registry/.meta 2>&1 >/dev/null) || |
|
193 | + die "/api/registry/.meta download failed: $err" |
|
194 | + |
|
195 | +if ! cmp -s "$metafile" "$metafile".old >/dev/null 2>&1; then |
|
196 | + mv "$metafile" "$metafile".old |
|
197 | + roafile=/var/db/openbgpd/dn42_roa_obgpd_46.conf |
|
198 | + if err=$(ftp -To "$roafile".new \ |
|
199 | + https://dn42.burble.com/roa/dn42_roa_obgpd_46.conf \ |
|
200 | + 2>&1 >/dev/null); then |
|
201 | + mv "$roafile".new "$roafile" |
|
202 | + bgpctl reload |
|
203 | + else |
|
204 | + die "ROA download failed: $err" |
|
205 | + fi |
|
206 | +else |
|
207 | + logger -cisp user.info "${0##*/}: registry unchanged, not reloading" |
|
208 | +fi |
|
123 | 209 | ``` |
124 | 210 | |
125 | -Include it in `/etc/bgpd.conf`: |
|
211 | +### `/var/cron/tabs/root` |
|
126 | 212 | ```conf |
127 | -# defines roat-set, see _rpki-client crontab |
|
128 | -include "/etc/dn42.roa-set" |
|
213 | +~ * * * * -ns /root/openbgpd-roa-update.sh |
|
129 | 214 | ``` |
130 | 215 | |
131 | 216 | # Looking glass |
132 | 217 | This is mostly OpenBSD specific since [bgplg(8)](http://man.openbsd.org/bgplg.8) and [httpd(8)](http://man.openbsd.org/httpd.8) ship as part of the operating system. |
133 | -The **bgplg** manual contains the few steps and example [httpd.conf(5)](http://man.openbsd.org/httpd.conf.5) required to enable the looking glass. |
|
218 | +The **bgplg** manual contains the steps and example [httpd.conf(5)](http://man.openbsd.org/httpd.conf.5) required to enable the looking glass. |
|
134 | 219 | |
135 | 220 | See <https://t4-2.high5.nl/bgplg> for a running instance operating within DN42. |