howto/vyos1.5.x.md
... ...
@@ -0,0 +1,624 @@
1
+# VyOS 1.5.x circinus
2
+
3
+VyOS is an open source software router. It is feature rich and supports
4
+multiple deployment options such as physical hardware (old PCs) or a VPC/VM.
5
+
6
+VyOS offers three release channels:
7
+
8
+- **Rolling release** – bleeding-edge nightly builds with all the latest
9
+ features (including WireGuard), but no stability guarantees: anything may
10
+ change and experimental features can be added or removed at any time. Best
11
+ for development and testing only.
12
+- **VyOS Stream** – a quarterly technology-preview / quality-gate on the way
13
+ to the 1.5 (circinus) LTS. It carries most of the upcoming LTS features but
14
+ is considerably more stable than the rolling release, since features are
15
+ only backported once their design is settled. Stream images are named after
16
+ their release year and month, e.g. `vyos-2026.03-generic-amd64.iso`.
17
+- **LTS** – the stable long-term-support release, available to subscribers
18
+ (or via the no-cost subscription for those who qualify, or by building from
19
+ source).
20
+
21
+This guide was written and tested on **VyOS Stream (circinus), version
22
+2026.03**.
23
+
24
+Rolling images: <https://vyos.net/get/nightly-builds/><br>
25
+VyOS Stream images: <https://vyos.net/get/stream/>
26
+
27
+This guide uses the following example values throughout. Replace the
28
+**operator-assigned** ones with your own DN42 registry allocation; the
29
+**DN42-wide** ranges are fixed and must be left as-is.
30
+
31
+| Example value | Meaning | Change it? |
32
+| ------------------------ | ---------------------------------------- | -------------------------- |
33
+| `4242421234` | **Your** ASN | Yes |
34
+| `4242424242` | **Your peer's** ASN | Yes |
35
+| `172.20.20.0/27` | **Your assigned IPv4** (`inetnum`) | Yes |
36
+| `fd88:9deb:a69e::/48` | **Your assigned IPv6** (`inet6num`) | Yes |
37
+| `10.0.0.0/8`, `172.20.0.0/14`, `172.31.0.0/16` | Whole DN42 IPv4 space | No, leave as-is |
38
+| `fd00::/8` | Whole DN42 IPv6 space | No, leave as-is |
39
+| `172.20.0.53`, `172.23.0.53` | DN42 recursive resolvers | No, leave as-is |
40
+
41
+## Firewall
42
+
43
+### Firewall Baseline (stateful global)
44
+
45
+By default, VyOS performs **stateless** filtering: with no ruleset nothing is filtered, and once a drop-by-default ruleset is applied, return traffic of established sessions is **not** allowed back automatically. We enable stateful inspection globally so we don't have to repeat established/related rules in every ruleset.
46
+
47
+```sh
48
+set firewall global-options state-policy established action 'accept'
49
+set firewall global-options state-policy related action 'accept'
50
+```
51
+
52
+### Edge: accept invalid
53
+
54
+We also accept `invalid` packets on our network's edge. This should **not** become common practice elsewhere. It is specific to a DN42 BGP edge, where conntrack-untracked traffic (including BGP) can otherwise be wrongly classified as `invalid` and dropped.
55
+
56
+```sh
57
+set firewall global-options state-policy invalid action 'accept'
58
+```
59
+
60
+### Per-WireGuard-interface rulesets
61
+
62
+These create **in** (transit) and **local** (to-the-router) baseline templates to be applied to every WireGuard interface facing a peer.
63
+
64
+Only the two `My-Assigned-Space-*` lines need editing to match your own registry prefixes; the `Allowed-Transit-*` ranges are the whole of DN42 and stay as-is.
65
+
66
+```sh
67
+# --- Groups v4 ---
68
+set firewall group network-group Allowed-Transit-v4 network '10.0.0.0/8'
69
+set firewall group network-group Allowed-Transit-v4 network '172.20.0.0/14'
70
+set firewall group network-group Allowed-Transit-v4 network '172.31.0.0/16'
71
+set firewall group network-group My-Assigned-Space-v4 network '172.20.20.0/27'
72
+
73
+# --- Groups v6 ---
74
+set firewall group ipv6-network-group Allowed-Transit-v6 network 'fd00::/8'
75
+set firewall group ipv6-network-group My-Assigned-Space-v6 network 'fd88:9deb:a69e::/48'
76
+
77
+# --- Inbound / transit v4 ---
78
+set firewall ipv4 name Tunnels_In_v4 default-action 'drop'
79
+set firewall ipv4 name Tunnels_In_v4 default-log
80
+set firewall ipv4 name Tunnels_In_v4 rule 68 action 'drop'
81
+set firewall ipv4 name Tunnels_In_v4 rule 68 description 'Block Traffic to Operator Assigned IP Space'
82
+set firewall ipv4 name Tunnels_In_v4 rule 68 destination group network-group 'My-Assigned-Space-v4'
83
+set firewall ipv4 name Tunnels_In_v4 rule 68 log
84
+set firewall ipv4 name Tunnels_In_v4 rule 70 action 'accept'
85
+set firewall ipv4 name Tunnels_In_v4 rule 70 description 'Allow Peer Transit'
86
+set firewall ipv4 name Tunnels_In_v4 rule 70 destination group network-group 'Allowed-Transit-v4'
87
+set firewall ipv4 name Tunnels_In_v4 rule 70 source group network-group 'Allowed-Transit-v4'
88
+set firewall ipv4 name Tunnels_In_v4 rule 99 action 'drop'
89
+set firewall ipv4 name Tunnels_In_v4 rule 99 description 'Black Hole'
90
+set firewall ipv4 name Tunnels_In_v4 rule 99 log
91
+
92
+# --- Inbound / transit v6 ---
93
+set firewall ipv6 name Tunnels_In_v6 default-action 'drop'
94
+set firewall ipv6 name Tunnels_In_v6 default-log
95
+set firewall ipv6 name Tunnels_In_v6 rule 68 action 'drop'
96
+set firewall ipv6 name Tunnels_In_v6 rule 68 description 'Block Traffic to Operator Assigned IP Space'
97
+set firewall ipv6 name Tunnels_In_v6 rule 68 destination group network-group 'My-Assigned-Space-v6'
98
+set firewall ipv6 name Tunnels_In_v6 rule 68 log
99
+set firewall ipv6 name Tunnels_In_v6 rule 70 action 'accept'
100
+set firewall ipv6 name Tunnels_In_v6 rule 70 description 'Allow Peer Transit'
101
+set firewall ipv6 name Tunnels_In_v6 rule 70 destination group network-group 'Allowed-Transit-v6'
102
+set firewall ipv6 name Tunnels_In_v6 rule 70 source group network-group 'Allowed-Transit-v6'
103
+set firewall ipv6 name Tunnels_In_v6 rule 99 action 'drop'
104
+set firewall ipv6 name Tunnels_In_v6 rule 99 description 'Black Hole'
105
+set firewall ipv6 name Tunnels_In_v6 rule 99 log
106
+
107
+# --- Local / to the router v4 ---
108
+set firewall ipv4 name Tunnels_Local_v4 default-action 'drop'
109
+set firewall ipv4 name Tunnels_Local_v4 rule 50 action 'accept'
110
+set firewall ipv4 name Tunnels_Local_v4 rule 50 protocol 'icmp'
111
+set firewall ipv4 name Tunnels_Local_v4 rule 61 action 'accept'
112
+set firewall ipv4 name Tunnels_Local_v4 rule 61 description 'Allow BGP'
113
+set firewall ipv4 name Tunnels_Local_v4 rule 61 destination port '179'
114
+set firewall ipv4 name Tunnels_Local_v4 rule 61 protocol 'tcp'
115
+set firewall ipv4 name Tunnels_Local_v4 rule 99 action 'drop'
116
+set firewall ipv4 name Tunnels_Local_v4 rule 99 description 'Black Hole'
117
+set firewall ipv4 name Tunnels_Local_v4 rule 99 log
118
+
119
+# --- Local / to the router v6 ---
120
+set firewall ipv6 name Tunnels_Local_v6 default-action 'drop'
121
+set firewall ipv6 name Tunnels_Local_v6 rule 50 action 'accept'
122
+set firewall ipv6 name Tunnels_Local_v6 rule 50 protocol 'ipv6-icmp'
123
+set firewall ipv6 name Tunnels_Local_v6 rule 61 action 'accept'
124
+set firewall ipv6 name Tunnels_Local_v6 rule 61 description 'Allow BGP'
125
+set firewall ipv6 name Tunnels_Local_v6 rule 61 destination port '179'
126
+set firewall ipv6 name Tunnels_Local_v6 rule 61 protocol 'tcp'
127
+set firewall ipv6 name Tunnels_Local_v6 rule 99 action 'drop'
128
+set firewall ipv6 name Tunnels_Local_v6 rule 99 description 'Black Hole'
129
+set firewall ipv6 name Tunnels_Local_v6 rule 99 log
130
+```
131
+
132
+## WireGuard
133
+
134
+### Setup Keys
135
+
136
+You can generate one keypair and reuse it for every WireGuard peering, or generate a different one per peering.
137
+
138
+```sh
139
+generate pki wireguard key-pair
140
+
141
+# Output give public keys like: UcqcZsJvq1MlYgo3gObjaJ8FH+N7wkfV+EH3YDAMyRE=
142
+```
143
+
144
+To generate **and install** a unique keypair on an interface in one shot (from `configure` mode, top level):
145
+
146
+A WireGuard interface name on VyOS must be `wg` followed by digits only (letters are rejected, so `wgpeer` won't work). The name has no protocol meaning, but since interface names must be unique, the DN42 convention is to name each tunnel after the peer's ASN (for example `wg4242424242`, or a short form). That way the name tells you who's on the other end. Don't name a tunnel after your own ASN: it would collide the moment you add a second peer and wouldn't identify anything.
147
+
148
+```sh
149
+run generate pki wireguard key-pair install interface wg4242
150
+# 1 value(s) installed. Use "compare" to see pending changes, and "commit" to apply.
151
+# Corresponding public-key to use on peer system is: 'UcqcZsJvq1MlYgo3gObjaJ8FH+N7wkfV+EH3YDAMyRE='
152
+```
153
+
154
+To retrieve the public key later (op-mode):
155
+
156
+```sh
157
+run show interfaces wireguard wg4242 public-key
158
+
159
+# Output example:
160
+# UcqcZsJvq1MlYgo3gObjaJ8FH+N7wkfV+EH3YDAMyRE=
161
+```
162
+
163
+### Configure the peer's tunnel
164
+
165
+This example assumes your ASN is `4242421234` and your peer's ASN is `4242424242`.
166
+Interface naming follows the DN42 convention `wg<peer-ASN-last-4-digits>` -> `wg4242`.
167
+
168
+```sh
169
+set interfaces wireguard wg4242 description 'AS4242424242 - My Peer'
170
+
171
+# DN42 port convention:
172
+# - YOUR listen port = 2 + last 4 digits of your PEER's ASN -> 2 + 4242 = 24242
173
+# - the port you point to = 2 + last 4 digits of YOUR ASN -> 2 + 1234 = 21234
174
+set interfaces wireguard wg4242 port '24242'
175
+
176
+# NOTE: the private key is already installed by
177
+# 'run generate pki wireguard key-pair install interface wg4242'
178
+# Do NOT re-set it here, or you will overwrite your real key.
179
+
180
+# Your link-local IPv6 (the one you give to the auto-peering portal).
181
+# Arbitrary, but must be inside fe80::/64, e.g. derived from your ASN.
182
+set interfaces wireguard wg4242 address 'fe80::1234/64'
183
+
184
+# (No IPv4 on the tunnel: with extended-next-hop enabled, your DN42 IPv4
185
+# lives on the LAN interface instead, anchored by a blackhole route,
186
+# see the BGP prerequisites section below.)
187
+
188
+# Your peer's clearnet endpoint, must be an IP literal, not a DNS name.
189
+# Resolve the peer's FQDN first and use the resulting IP.
190
+set interfaces wireguard wg4242 peer mypeer address '<peer endpoint IP>'
191
+set interfaces wireguard wg4242 peer mypeer port '21234'
192
+
193
+# Allow everything and rely on the firewall + BGP for control
194
+set interfaces wireguard wg4242 peer mypeer allowed-ips '0.0.0.0/0'
195
+set interfaces wireguard wg4242 peer mypeer allowed-ips '::/0'
196
+
197
+# Your peer's WireGuard public key (from the auto-peering result)
198
+set interfaces wireguard wg4242 peer mypeer public-key '<peer wireguard public key>'
199
+
200
+# Helps the BGP session come up reliably
201
+set interfaces wireguard wg4242 peer mypeer persistent-keepalive '60'
202
+
203
+# Remove the auto-generated link-local so the BGP session sources from YOUR
204
+# chosen link-local only. With two link-locals on the interface, BGP may source
205
+# from the wrong one and the peer won't recognize the session.
206
+set interfaces wireguard wg4242 ipv6 address no-default-link-local
207
+```
208
+
209
+**Placeholders to replace with your own values:**
210
+
211
+| Placeholder | Meaning |
212
+| ----------------------------- | ----------------------------------------------------- |
213
+| `wg4242` | interface name = `wg` + your peer's last 4 ASN digits |
214
+| `24242` | your listen port = `2` + peer's last 4 ASN digits |
215
+| `fe80::1234/64` | your link-local (the one you gave the portal) |
216
+| `<peer endpoint IP>` | peer's clearnet endpoint, as an IP literal |
217
+| `21234` | peer's port = `2` + your last 4 ASN digits |
218
+| `<peer wireguard public key>` | from the auto-peering result |
219
+
220
+### Apply the firewall rulesets to the tunnel
221
+
222
+```sh
223
+# Group every DN42 peer tunnel together (add future wgXXXX interfaces here)
224
+set firewall group interface-group DN42-Peers interface 'wg4242'
225
+
226
+# Transit traffic (forward hook) -> Tunnels_In_*
227
+set firewall ipv4 forward filter rule 10 description 'DN42 peers transit'
228
+set firewall ipv4 forward filter rule 10 action 'jump'
229
+set firewall ipv4 forward filter rule 10 inbound-interface group 'DN42-Peers'
230
+set firewall ipv4 forward filter rule 10 jump-target 'Tunnels_In_v4'
231
+set firewall ipv6 forward filter rule 10 description 'DN42 peers transit'
232
+set firewall ipv6 forward filter rule 10 action 'jump'
233
+set firewall ipv6 forward filter rule 10 inbound-interface group 'DN42-Peers'
234
+set firewall ipv6 forward filter rule 10 jump-target 'Tunnels_In_v6'
235
+
236
+# Traffic to the router itself, e.g. BGP (input hook) -> Tunnels_Local_*
237
+set firewall ipv4 input filter rule 10 description 'DN42 peers to router'
238
+set firewall ipv4 input filter rule 10 action 'jump'
239
+set firewall ipv4 input filter rule 10 inbound-interface group 'DN42-Peers'
240
+set firewall ipv4 input filter rule 10 jump-target 'Tunnels_Local_v4'
241
+set firewall ipv6 input filter rule 10 description 'DN42 peers to router'
242
+set firewall ipv6 input filter rule 10 action 'jump'
243
+set firewall ipv6 input filter rule 10 inbound-interface group 'DN42-Peers'
244
+set firewall ipv6 input filter rule 10 jump-target 'Tunnels_Local_v6'
245
+```
246
+
247
+You will also want a plain accept for your own LAN, both for traffic transiting the router and for traffic to the router itself:
248
+
249
+```sh
250
+set firewall ipv4 forward filter rule 20 description 'LAN forward'
251
+set firewall ipv4 forward filter rule 20 action 'accept'
252
+set firewall ipv4 forward filter rule 20 inbound-interface name 'eth2'
253
+set firewall ipv4 input filter rule 20 description 'LAN to router'
254
+set firewall ipv4 input filter rule 20 action 'accept'
255
+set firewall ipv4 input filter rule 20 inbound-interface name 'eth2'
256
+set firewall ipv6 forward filter rule 20 description 'LAN forward v6'
257
+set firewall ipv6 forward filter rule 20 action 'accept'
258
+set firewall ipv6 forward filter rule 20 inbound-interface name 'eth2'
259
+set firewall ipv6 input filter rule 20 description 'LAN to router v6'
260
+set firewall ipv6 input filter rule 20 action 'accept'
261
+set firewall ipv6 input filter rule 20 inbound-interface name 'eth2'
262
+```
263
+
264
+## BGP
265
+
266
+### Prerequisites: anchor your prefixes (blackhole + LAN address)
267
+
268
+BGP only advertises a prefix from a `network` statement if a route of the **exact
269
+same length** already exists in the routing table. Instead of a dummy interface,
270
+we anchor each registry prefix with a static **blackhole** route. A blackhole
271
+route is always present regardless of interface or tunnel state, so BGP keeps
272
+advertising your aggregate even when a link flaps.
273
+
274
+Your actual DN42 addresses live on your **LAN-facing interface**, where your
275
+clients and services sit. Traffic to real hosts follows the connected route;
276
+traffic to unused addresses in the range falls through to the blackhole and is
277
+dropped, so you never leak or loop packets for hosts that don't exist.
278
+
279
+```sh
280
+# DN42 addresses on the LAN interface (adjust eth2 to your LAN NIC).
281
+# The /27 gives you the IPv4 LAN; the /64 is one segment carved from your /48.
282
+set interfaces ethernet eth2 description 'LAN services DN42'
283
+set interfaces ethernet eth2 address '172.20.20.1/27'
284
+set interfaces ethernet eth2 address 'fd88:9deb:a69e:1::1/64'
285
+
286
+# Always-up aggregate routes so BGP can advertise the exact registry prefixes,
287
+# independent of any interface or tunnel state.
288
+set protocols static route 172.20.20.0/27 blackhole
289
+set protocols static route6 fd88:9deb:a69e::/48 blackhole
290
+```
291
+
292
+Here the IPv4 LAN is a `/27` matching your `inetnum`, and the IPv6 `/48`
293
+blackhole matches your `inet6num` exactly, which is what the BGP `network`
294
+statements need. The `/64` on the LAN is just one usable segment of that `/48`
295
+for client autoconfiguration.
296
+
297
+Verify:
298
+
299
+```sh
300
+run show interfaces ethernet eth2
301
+run show ip route 172.20.20.0/27
302
+run show ipv6 route fd88:9deb:a69e::/48
303
+```
304
+
305
+### Initial Router Setup
306
+
307
+```sh
308
+# Your ASN
309
+set protocols bgp system-as '4242421234'
310
+
311
+# Advertise your EXACT registry prefixes (a more-specific subnet may be filtered by peers)
312
+set protocols bgp address-family ipv4-unicast network '172.20.20.0/27'
313
+set protocols bgp address-family ipv6-unicast network 'fd88:9deb:a69e::/48'
314
+
315
+# Router-id = your lowest DN42 IPv4
316
+set protocols bgp parameters router-id '172.20.20.1'
317
+```
318
+
319
+### Neighbor: MP-BGP over IPv6 link-local + extended next-hop
320
+
321
+One peer-group carries the address families, the extended-next-hop capability, and `remote-as external` (every DN42 peer is a different external AS).
322
+
323
+```sh
324
+# Shared peer-group for all DN42 link-local MP-BGP peers
325
+set protocols bgp peer-group dn42 remote-as 'external'
326
+set protocols bgp peer-group dn42 address-family ipv4-unicast
327
+set protocols bgp peer-group dn42 address-family ipv6-unicast
328
+set protocols bgp peer-group dn42 capability extended-nexthop
329
+
330
+# The peer, addressed on the peer's link-local, scoped to the tunnel interface.
331
+# Replace fe80::5678 with the link-local your peer's auto-peering portal gave you
332
+# (this is the PEER's link-local, not yours).
333
+set protocols bgp neighbor fe80::5678 interface source-interface 'wg4242'
334
+set protocols bgp neighbor fe80::5678 peer-group 'dn42'
335
+```
336
+
337
+Address the peer's link-local **explicitly** as shown above. Avoid unnumbered
338
+peering (`neighbor wg4242 interface v6only`): unnumbered relies on the peer
339
+sending IPv6 Router Advertisements to auto-discover its link-local, and some
340
+peers (for example those running BIRD) do not send them, so the session stays
341
+`Idle` and never sends a single packet.
342
+
343
+Also, do not add `remote-as` on the neighbor when the peer-group already sets
344
+`remote-as external`; VyOS rejects it with `cannot override remote-as of
345
+peer-group`.
346
+
347
+### Verify
348
+
349
+```sh
350
+run show bgp summary # both address families
351
+run show bgp ipv4 summary
352
+run show bgp ipv6 summary
353
+```
354
+
355
+A healthy session shows a number (received prefixes) under `State/PfxRcd`, not `Connect`/`Active`:
356
+
357
+```txt
358
+Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
359
+fe80::5678 4 4242424242 1921 1850 1103 0 0 00:00:08 1097 1098 N/A
360
+```
361
+
362
+Once the session is `Established`, confirm end-to-end routing to DN42. Because the
363
+router has no DN42 IPv4 on the tunnel, source pings from your DN42 LAN address:
364
+
365
+```sh
366
+run ping 172.20.0.53 source-address 172.20.20.1 count 3
367
+run ping fd42:d42:d42:53::1 source-address fd88:9deb:a69e:1::1 count 3
368
+```
369
+
370
+A reply (with `ttl` < 64, showing it crossed DN42 hops) confirms the extended-next-hop
371
+is working, IPv4 destinations resolved via an IPv6 next-hop over the tunnel.
372
+
373
+## RPKI / ROA Filtering
374
+
375
+On DN42, RPKI lets your router reject route announcements whose origin AS doesn't match the registry (likely hijacks). You run a small **RTR cache** that downloads the DN42 ROA table, and point VyOS at it.
376
+
377
+Cloudflare's GoRTR is archived; DN42 now uses **StayRTR** (`rpki/stayrtr`), a
378
+drop-in fork with the same flags, and the ROA file is still published by Burble.
379
+StayRTR has no `-verify` flag (GoRTR had one): a stray `-verify=false` makes the
380
+container exit immediately (`Exited (2)`) and just print its help. Valid StayRTR
381
+args: `-cache <url> -checktime=false [-bind :8082]`.
382
+
383
+### Option A: Run StayRTR as a container on VyOS
384
+
385
+```sh
386
+# op-mode: pull the image
387
+run add container image rpki/stayrtr
388
+```
389
+
390
+```sh
391
+# config-mode: an internal-only network for the cache
392
+set container network rpki prefix '172.16.2.0/24'
393
+
394
+# the StayRTR container, note: flags go in `arguments`, not `command`
395
+set container name stayrtr image 'rpki/stayrtr'
396
+set container name stayrtr arguments '-cache https://dn42.burble.com/roa/dn42_roa_46.json -checktime=false -bind :8082'
397
+set container name stayrtr network rpki address '172.16.2.10'
398
+set container name stayrtr restart 'on-failure'
399
+```
400
+
401
+### Option B: Run StayRTR on a separate host (Docker)
402
+
403
+```sh
404
+docker run -d --name dn42-rpki --restart=always -p 8082:8082 \
405
+ rpki/stayrtr -cache https://dn42.burble.com/roa/dn42_roa_46.json \
406
+ -checktime=false -bind :8082
407
+```
408
+
409
+### Point VyOS at the cache
410
+
411
+```sh
412
+set protocols rpki cache 172.16.2.10 port '8082'
413
+set protocols rpki cache 172.16.2.10 preference '1'
414
+```
415
+
416
+*(Use the container IP `172.16.2.10` for Option A, or the separate host's IP for Option B.)*
417
+
418
+Verify the cache is connected and the table is populated:
419
+
420
+```sh
421
+run show rpki cache-connection
422
+run show rpki prefix-table
423
+```
424
+
425
+After pointing VyOS at the cache, you may need to force FRR to (re)connect. Otherwise it may stay
426
+on "No connection" because it gave up while the container was starting:
427
+
428
+```sh
429
+run reset rpki
430
+```
431
+
432
+Then re-verify:
433
+
434
+```sh
435
+run show rpki cache-connection # expect: (connected)
436
+run show rpki prefix-table # expect: thousands of entries
437
+```
438
+
439
+### Filtering route-map (RPKI + DN42 range sanity, combined)
440
+
441
+A single route-map does both jobs: drop RPKI-`invalid` prefixes **and** only accept prefixes that fall inside DN42's address space (a bogon guard RPKI alone doesn't give you).
442
+
443
+The `le '32'` on IPv4 is deliberate: DN42's recursive resolvers are announced as
444
+host routes (`172.20.0.53/32`, `172.23.0.53/32`). A stricter bound would silently
445
+drop every `/32`, so those resolvers never enter your table and DNS later fails
446
+for no obvious reason. Keep `le '32'` (and `le '64'` on IPv6) so host routes are
447
+accepted.
448
+
449
+```sh
450
+# --- Prefix-lists: DN42's allocated ranges ---
451
+set policy prefix-list DN42-v4 rule 10 action 'permit'
452
+set policy prefix-list DN42-v4 rule 10 prefix '172.20.0.0/14'
453
+set policy prefix-list DN42-v4 rule 10 le '32'
454
+set policy prefix-list DN42-v4 rule 20 action 'permit'
455
+set policy prefix-list DN42-v4 rule 20 prefix '10.0.0.0/8'
456
+set policy prefix-list DN42-v4 rule 20 le '32'
457
+
458
+set policy prefix-list6 DN42-v6 rule 10 action 'permit'
459
+set policy prefix-list6 DN42-v6 rule 10 prefix 'fd00::/8'
460
+set policy prefix-list6 DN42-v6 rule 10 le '64'
461
+
462
+# --- One combined filter, used both import and export ---
463
+set policy route-map DN42-PEERING rule 5 action 'deny'
464
+set policy route-map DN42-PEERING rule 5 description 'Reject RPKI invalid (possible hijack)'
465
+set policy route-map DN42-PEERING rule 5 match rpki 'invalid'
466
+set policy route-map DN42-PEERING rule 20 action 'permit'
467
+set policy route-map DN42-PEERING rule 20 description 'Accept DN42 IPv4 ranges'
468
+set policy route-map DN42-PEERING rule 20 match ip address prefix-list 'DN42-v4'
469
+set policy route-map DN42-PEERING rule 21 action 'permit'
470
+set policy route-map DN42-PEERING rule 21 description 'Accept DN42 IPv6 ranges'
471
+set policy route-map DN42-PEERING rule 21 match ipv6 address prefix-list 'DN42-v6'
472
+set policy route-map DN42-PEERING rule 99 action 'deny'
473
+set policy route-map DN42-PEERING rule 99 description 'Drop everything else'
474
+```
475
+
476
+The same map works for both address families: a `match ip address` rule simply
477
+doesn't match IPv6 routes (and vice-versa), so each AF falls through to its own
478
+rule. The `le '32'` / `le '64'` also caps absurdly long prefixes; tighten or
479
+loosen to taste.
480
+
481
+### Apply the filter to the peer-group (not per neighbor)
482
+
483
+Because every DN42 peer shares the `dn42` peer-group, you apply the filter **once** and all peers inherit it:
484
+
485
+```sh
486
+set protocols bgp peer-group dn42 address-family ipv4-unicast route-map import 'DN42-PEERING'
487
+set protocols bgp peer-group dn42 address-family ipv4-unicast route-map export 'DN42-PEERING'
488
+set protocols bgp peer-group dn42 address-family ipv6-unicast route-map import 'DN42-PEERING'
489
+set protocols bgp peer-group dn42 address-family ipv6-unicast route-map export 'DN42-PEERING'
490
+commit
491
+```
492
+
493
+### Apply & verify
494
+
495
+Route-maps only affect new updates, so refresh the session, then check.
496
+
497
+```sh
498
+vtysh -c "clear bgp * soft"
499
+show bgp ipv4 summary
500
+show bgp ipv6 summary
501
+vtysh -c "show bgp ipv4 unicast 172.20.0.0/14 longer-prefixes" # spot-check learned routes
502
+```
503
+
504
+Your `State/PfxRcd` count may drop slightly after filtering, that's the invalid/out-of-range prefixes being rejected, which is exactly the point.
505
+
506
+To inspect what a specific neighbor sent you before filtering (handy when a route
507
+you expect is missing), enable soft-reconfiguration inbound and look at the
508
+filtered routes:
509
+
510
+```sh
511
+set protocols bgp neighbor fe80::5678 address-family ipv4-unicast soft-reconfiguration inbound
512
+commit
513
+```
514
+
515
+```sh
516
+vtysh -c "show bgp ipv4 unicast neighbors fe80::5678 filtered-routes"
517
+```
518
+
519
+## DNS Resolution (resolving `.dn42`)
520
+
521
+Once routing works, you'll want to resolve DN42 names like `git.dn42`. DN42 runs
522
+recursive resolvers (for example `172.20.0.53` and `172.23.0.53`) that also
523
+resolve the clearnet, so they can serve as your only upstream if you want
524
+everything to go through DN42.
525
+
526
+We run a small DNS forwarder on the router itself. LAN clients query the router,
527
+and the router forwards to the DN42 resolvers.
528
+
529
+Two things to get right, both reflected in the config below:
530
+
531
+Queries the router generates itself leave through the WireGuard tunnel, but the
532
+kernel has no DN42 IPv4 on that interface, so by default it picks your public WAN
533
+IP as the source. The DN42 resolver then has nowhere to send its reply and the
534
+query times out. `source-address` forces the forwarder to source from your DN42
535
+LAN address.
536
+
537
+Use the **global** `name-server` form, not conditional `domain` forwarding.
538
+VyOS turns `domain` entries into pdns `forward-zones=` (RD=0), which asks the
539
+upstream only for what it is authoritative for. The DN42 resolvers are recursive,
540
+not authoritative for `.dn42`, so they answer `REFUSED`, surfaced to the client
541
+as `SERVFAIL`. Global `name-server` entries become `forward-zones-recurse`
542
+(RD=1, the `+` prefix in the generated zone file), which is what recursive
543
+upstreams expect. Since we want all DNS to go through DN42 anyway, the global
544
+form is both simpler and correct.
545
+
546
+### Config
547
+
548
+```sh
549
+# Listen on the router's DN42 LAN address; only the LAN may query us
550
+set service dns forwarding listen-address '172.20.20.1'
551
+set service dns forwarding allow-from '172.20.20.0/27'
552
+
553
+# Source outgoing queries from our DN42 address
554
+set service dns forwarding source-address '172.20.20.1'
555
+
556
+# Global upstreams = DN42 recursive resolvers (no 'domain' entries).
557
+# These resolve both .dn42 and the clearnet.
558
+set service dns forwarding name-server '172.20.0.53'
559
+set service dns forwarding name-server '172.23.0.53'
560
+
561
+# DN42 resolvers are not DNSSEC-signed to the ICANN root; validation would
562
+# SERVFAIL .dn42, so turn it off on the forwarder.
563
+set service dns forwarding dnssec 'off'
564
+commit
565
+```
566
+
567
+### Verify
568
+
569
+From the router, query your own forwarder explicitly (not the system resolver):
570
+
571
+```sh
572
+dig @172.20.20.1 git.dn42 A # expect NOERROR + an answer
573
+dig @172.20.20.1 example.com A # clearnet must work too
574
+```
575
+
576
+If you get `SERVFAIL`, check the generated zone file: the `.dn42` upstream must be
577
+the catch-all `+.` line (recursive). A separate `dn42=` line without the `+`
578
+prefix means a stray `domain` entry slipped in and should be removed.
579
+
580
+```sh
581
+sudo cat /run/pdns-recursor/recursor.forward-zones.conf
582
+# +.=172.20.0.53:53, 172.23.0.53:53 <- good, recursive
583
+# dn42=172.20.0.53:53, ... <- bad, non-recursive, remove the 'domain' entry
584
+```
585
+
586
+To confirm the source address is correct, capture an outgoing query; the source
587
+must be your DN42 address, not your public WAN IP:
588
+
589
+```sh
590
+sudo tcpdump -ni any port 53 and host 172.20.0.53
591
+# 172.20.20.1.xxxxx > 172.20.0.53.53 <- good
592
+# <public IP>.xxxxx > 172.20.0.53.53 <- bad, source-address not applied
593
+```
594
+
595
+### Hand DNS to LAN clients
596
+
597
+Point your DHCP clients at the forwarder and drop the clearnet resolvers (which
598
+don't know `.dn42`):
599
+
600
+```sh
601
+set service dhcp-server shared-network-name LAN subnet 172.20.20.0/27 option name-server '172.20.20.1'
602
+commit
603
+```
604
+
605
+With a single peer, all DNS (clearnet included) now depends on that BGP session
606
+and the DN42 resolvers. If the peer drops, the LAN loses DNS entirely. Add a
607
+second peer (and ideally resolvers reachable over different paths) before relying
608
+on this, or keep one clearnet resolver lower in the list as a fallback, at the
609
+cost of it not resolving `.dn42`.
610
+
611
+## Credits
612
+
613
+This How-To has to be considered a work-in-progress by **mathys-lopinto**
614
+The doc was updated with the help of Claude AI.
615
+
616
+It's based on the original VyOS How-To made by **Matwolf** and **bri**: [How-To/vyos1.4.x](/howto/vyos1.4.x).
617
+
618
+The commands in this page have been adapted to be compatible with the new version of VyOS 1.5.x (circinus) and to include configurations for IPv6 (MP-BGP over link-local and extended next-hop).
619
+
620
+If you have any questions or suggestions please reach out.
621
+
622
+## See also
623
+
624
+[WireGuard](https://docs.vyos.io/en/latest/configuration/interfaces/wireguard.html) and [BGP](https://docs.vyos.io/en/latest/configuration/protocols/bgp.html) in the official VyOS documentation.
... ...
\ No newline at end of file