diff options
| author | Yuriy Andamasov <yuriy@vyos.io> | 2026-07-11 10:34:18 +0300 |
|---|---|---|
| committer | Yuriy Andamasov <yuriy@vyos.io> | 2026-07-11 10:34:18 +0300 |
| commit | 028cba2b881ba1beeaa21f6d0fd5eccf7fdc2f25 (patch) | |
| tree | feb0c9d7ee29cca29fcbe309e6b7242862d272e9 | |
| parent | 9e38b7190a285c7e2e3590d0381ad7892d5b0e8c (diff) | |
| parent | fa98eb5d526599021235c9cec929e99260f61d97 (diff) | |
| download | vyos-documentation-028cba2b881ba1beeaa21f6d0fd5eccf7fdc2f25.tar.gz vyos-documentation-028cba2b881ba1beeaa21f6d0fd5eccf7fdc2f25.zip | |
Merge rolling into claude/pdf-image-conversion (combine constrained apt line: imagemagick, librsvg2-bin, poppler-utils)
🤖 Generated by [robots](https://vyos.io)
| -rw-r--r-- | .github/workflows/docs-build.yml | 44 | ||||
| -rw-r--r-- | docker/Dockerfile | 12 | ||||
| -rw-r--r-- | docs/configexamples/dmvpn-dualhub-dualcloud.md | 59 | ||||
| -rw-r--r-- | docs/configuration/vpn/dmvpn.md | 95 |
4 files changed, 169 insertions, 41 deletions
diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml index fc9a2239..bdb9e41d 100644 --- a/.github/workflows/docs-build.yml +++ b/.github/workflows/docs-build.yml @@ -56,15 +56,57 @@ jobs: cache-to: type=gha,mode=max - name: Build HTML + PDF in in-workflow-built container + env: + # pdflatex hard-errors ("! LaTeX Error: Unicode character ... not + # set up for use with LaTeX") on the Devanagari etymology text in + # docs/introducing/history.md, and separately cannot embed some + # pre-existing .webp images (no BoundingBox). latexmk's force mode + # (-f) plus non-interactive pdflatex (-interaction=nonstopmode) + # makes it skip both classes of per-glyph/per-image failure and + # finish the document instead of halting — this is how ReadTheDocs + # has always built this project's PDF (verified against the live + # docs.vyos.io PDF: same Devanagari glyphs blanked, same ~4 images + # embedded out of 2000+ pages, rather than a failed build). + # latexmk still exits non-zero in force mode even when it produces + # a complete PDF, so success below is verified by checking the + # produced artifact directly (exact filename + page count), not the + # command's exit code. A bare existence/size check would let a + # truncated-but-large PDF (LaTeX aborting partway through) pass, so + # the completeness signal is pdfinfo's page count instead of file + # size. The §14 retry-once is gated on artifact ABSENCE: latexmk -f + # exits non-zero even on a fully-produced PDF, so an unconditional + # `|| make latexpdf` would double the ~10-min LaTeX step on every + # forced success. Each `|| true` only swallows that expected + # non-zero exit; the validation below is the real success signal. + LATEXMKOPTS: -f + LATEXOPTS: -interaction=nonstopmode run: | set -eu docker run --rm -v "$PWD:/src" -w /src \ -e DOCS_VERSION_SLUG="${{ steps.matrix.outputs.slug }}" \ -e DOCS_VERSION_BRANCH="${{ github.ref_name }}" \ + -e LATEXMKOPTS \ + -e LATEXOPTS \ docs-build:local bash -c ' + set -e cd docs && make html if [ "${{ inputs.skip_pdf }}" != "true" ]; then - make latexpdf || make latexpdf # retry once (§14 LaTeX flakiness) + pdf=_build/latex/VyOS.pdf + make latexpdf || true + # retry ONLY when no artifact was produced (§14 LaTeX flakiness) — + # latexmk -f exits non-zero even on success, so exit code cannot gate this + [ -f "$pdf" ] || make latexpdf || true + [ -f "$pdf" ] || { echo "$pdf not produced — build genuinely failed"; exit 1; } + # Page-count floor as a completeness signal (a truncated forced-mode + # run can still leave behind a file that exists and is large). rolling + # is verified ~2000+ pages; 1.4/1.5 page counts have not been + # individually verified, so 1000 is a conservative floor intended to + # clear all three release branches without masking a real truncation. + pages=$(pdfinfo "$pdf" 2>/dev/null | awk "/^Pages:/{print \$2}") + case "$pages" in + ""|*[!0-9]*) pages=0 ;; + esac + [ "$pages" -ge 1000 ] || { echo "$pdf has $pages pages (<1000) — build genuinely failed"; exit 1; } fi' - name: Assemble artifact (nest under en/<slug>/, §7.1) diff --git a/docker/Dockerfile b/docker/Dockerfile index e0947ac7..8598b808 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -27,13 +27,15 @@ RUN apt-get update && apt-get install -y \ curl \ dos2unix -# Image-conversion toolchain for the PDF build (sphinx.ext.imgconverter via -# docker/im-convert.sh). Installed with --no-install-recommends (Trivy -# DS-0029) on a separate line: the texlive line above deliberately keeps -# recommends, which carry font packages LaTeX needs. +# PDF-build toolchain extras, installed with --no-install-recommends (Trivy +# DS-0029) on a separate line — the texlive line above deliberately keeps +# recommends, which carry font packages LaTeX needs: +# - imagemagick + librsvg2-bin: sphinx.ext.imgconverter via docker/im-convert.sh +# - poppler-utils: pdfinfo for the docs-build workflow's page-count validation RUN apt-get update && apt-get install -y --no-install-recommends \ imagemagick \ - librsvg2-bin + librsvg2-bin \ + poppler-utils RUN pip3 install --break-system-packages \ Sphinx \ diff --git a/docs/configexamples/dmvpn-dualhub-dualcloud.md b/docs/configexamples/dmvpn-dualhub-dualcloud.md index 20c1a064..d98f45d9 100644 --- a/docs/configexamples/dmvpn-dualhub-dualcloud.md +++ b/docs/configexamples/dmvpn-dualhub-dualcloud.md @@ -6,11 +6,12 @@ lastproofread: '2024-02-21' # DMVPN Dual HUB Dual Cloud -This document is to describe a basic setup to build DMVPN network with two Hubs and two clouds using DMVPN Phase3. +This document is to describe a basic setup to build DMVPN network with two Hubs +and two clouds using DMVPN Phase3. OSPF is used as routing protocol inside DMVPN. -In this example we use VyOS 1.5 as HUBs and Spokes (HUB-1, HUB-2, SPOKE-2, SPOKE-3) and Cisco IOSv 15.5(3)M (SPOKE-1) -as a Spoke. +In this example we use VyOS 1.5 as HUBs and Spokes (HUB-1, HUB-2, SPOKE-2, +SPOKE-3) and Cisco IOSv 15.5(3)M (SPOKE-1) as a Spoke. ## Network Topology @@ -79,10 +80,12 @@ set protocols static route 0.0.0.0/0 next-hop 10.0.13.1 ### NHRP configuration -The next step is to configure the NHRP protocol. In a Dual cloud network, every HUB has to be configured with one GRE -multipoint tunnel interface and every spoke has to be configured with two tunnel interfaces, one tunnel to each hub. -In this example tunnel networks are 10.100.100.0/24 for the first cloud and 10.100.101.0/24 for the second cloud. -But VyOS uses FRR for NHRP, that is why the tunnel address mask must be /32. +The next step is to configure the NHRP protocol. In a Dual cloud network, every +HUB has to be configured with one GRE multipoint tunnel interface and every +spoke has to be configured with two tunnel interfaces, one tunnel to each hub. +In this example tunnel networks are 10.100.100.0/24 for the first cloud +and 10.100.101.0/24 for the second cloud. But VyOS uses FRR for NHRP, that is +why the tunnel address mask must be /32. HUB-1 @@ -209,8 +212,10 @@ set protocols nhrp tunnel tun101 shortcut ### Overlay configuration -The last step is to configure the routing protocol. In this scenario, OSPF was chosen as the dynamic routing protocol. -But you can use iBGP or eBGP. To form fast convergence it is possible to use BFD protocol. +The last step is to configure the routing protocol. In this scenario, OSPF was +chosen as the dynamic routing protocol. +But you can use iBGP or eBGP. To form fast convergence it is possible to use +BFD protocol. HUB-1 @@ -380,10 +385,31 @@ SPOKE-1 tunnel protection ipsec profile gre_protection shared ``` +Because GRE forwarding in DMVPN is independent of IPSec, there can be conditions +when traffic is routed over the tunnel but there is no active IPsec SA for +a peer that would get that packets encrypted at that moment. +That may result in unencrypted GRE leaving the router. + +To prevent this, drop any GRE that is not protected by an outbound IPSec policy. +Add the following rule on the VyOS nodes (HUB-1, HUB-2, SPOKE-2 and SPOKE-3), +and make sure it comes before any rule that permits GRE. + +Note that this disables unencrypted GRE on the node entirely, +so any plain GRE tunnels without IPSec will stop working. +If your setup requires unencrypted GRE tunnels together with DMVPN, +you have to find a way to exempt their traffic from that filter. +See {ref}`vpn-dmvpn` for the full explanation. + +```none +set firewall ipv4 output filter rule 10 action 'drop' +set firewall ipv4 output filter rule 10 protocol 'gre' +set firewall ipv4 output filter rule 10 ipsec match-none-out +``` ## Monitoring -All spokes created IPSec tunnels to Hubs, are registered on Hubs using NHRP protocol and formed adjacency in OSPF. +All spokes created IPSec tunnels to Hubs, are registered on Hubs using NHRP +protocol and formed adjacency in OSPF. ```none vyos@HUB-1:~$ show vpn ipsec sa @@ -472,7 +498,8 @@ trace to 192.168.11.2, 8 hops max, press Ctrl+C to stop ``` First trace goes via HUB but the second goes directly from SPOKE-1 to SPOKE-2. -Now routing tables are changed. LAN networks 192.168.12.0/24 and 192.168.11.0/24 available directly via SPOKES. +Now routing tables are changed. LAN networks 192.168.12.0/24 +and 192.168.11.0/24 available directly via SPOKES. ```none vyos@SPOKE-2:~$ show ip route @@ -545,8 +572,10 @@ dmvpn-NHRPVPN-tun101-child up 5m58s 5K/4K 62/51 ## Summary -If one of the Hubs loses connectivity to the Internet, the other Hub will be available and take the main role. -This is a simple example where only one internet connection is used. But in the real world, there can be two -connections to the Internet. In this case, there is a recommendation to build each tunnel via each Internet connection, -choose the main cloud, and manipulate traffic via a routing protocol. It allows the creation failover on link-level +If one of the Hubs loses connectivity to the Internet, the other Hub will be +available and take the main role. This is a simple example where only one +internet connection is used. But in the real world, there can be two +connections to the Internet. In this case, there is a recommendation to build +each tunnel via each Internet connection, choose the main cloud, and manipulate +traffic via a routing protocol. It allows the creation failover on link-level connections too. diff --git a/docs/configuration/vpn/dmvpn.md b/docs/configuration/vpn/dmvpn.md index 4dc2c85f..dc0cd4f4 100644 --- a/docs/configuration/vpn/dmvpn.md +++ b/docs/configuration/vpn/dmvpn.md @@ -63,8 +63,8 @@ set interfaces tunnel tun100 source-interface 'eth0' :::{note} The IP-address is assigned as host prefix to tunnel interface. - NHRP will automatically create additional host routes pointing to tunnel interface - when a connection with these hosts is established. + NHRP will automatically create additional host routes pointing to tunnel + interface when a connection with these hosts is established. ::: The tunnel interface subnet prefix should be announced by routing protocol @@ -114,12 +114,13 @@ then destination NBMA address (or addresses) are learnt dynamically. * **network-id** - NHRP network id <1-4294967295> -Enable NHRP on this interface and set the interface’s network ID. The network ID -is used to allow creating multiple nhrp domains on a router when multiple interfaces -are configured on the router. Interfaces configured with the same ID are part of the -same logical NBMA network. The ID is a local only parameter and is not sent to other -NHRP nodes and so IDs on different nodes do not need to match. When NHRP packets are -received on an interface they are assigned to the local NHRP domain for that interface. +Enable NHRP on this interface and set the interface’s network ID. +The network ID is used to allow creating multiple nhrp domains on a router when +multiple interfaces are configured on the router. Interfaces configured with +the same ID are part of the same logical NBMA network. The ID is a local only +parameter and is not sent to other NHRP nodes and so IDs on different nodes +do not need to match. When NHRP packets are received on an interface they +are assigned to the local NHRP domain for that interface. ``` ```{cfgcmd} set protocols nhrp tunnel \<tunnel\> nhs tunnel-ip \<tunnel-ip\> nbma \<nbma-ip\> @@ -127,39 +128,40 @@ received on an interface they are assigned to the local NHRP domain for that int * **tunnel-ip** - Tunnel ip address in format **x.x.x.x** or **dynamic** * **nbma-ip** - NBMA ip address in format **x.x.x.x** -Configure the Next Hop Server address and its NBMA address. If dynamic is specified -then Next Hop Server can have dynamic address which maps to its NBMA address. +Configure the Next Hop Server address and its NBMA address. If dynamic is +specified then Next Hop Server can have dynamic address which maps to +its NBMA address. ``` ```{cfgcmd} set protocols nhrp tunnel \<tunnel\> redirect This enable redirect replies on the NHS similar to ICMP redirects except this is -managed by the nhrp protocol. This setting allows spokes to communicate with each -others directly. +managed by the nhrp protocol. This setting allows spokes to communicate with +each others directly. ``` ```{cfgcmd} set protocols nhrp tunnel \<tunnel\> registration-no-unique -Allow the client to not set the unique flag in the NHRP packets. This is useful when -a station has a dynamic IP address that could change over time. +Allow the client to not set the unique flag in the NHRP packets. This is useful +when a station has a dynamic IP address that could change over time. ``` ```{cfgcmd} set protocols nhrp tunnel \<tunnel\> shortcut -Enable shortcut (spoke-to-spoke) tunnels to allow NHC to talk to each others directly -after establishing a connection without going through the hub. +Enable shortcut (spoke-to-spoke) tunnels to allow NHC to talk to each others +directly after establishing a connection without going through the hub. ``` ### IPSEC configuration -- Please refer to the {ref}`ipsec_general` documentation for the individual IPSec - related options. +- Please refer to the {ref}`ipsec_general` documentation for the individual + IPSec related options. :::{note} NHRP daemon based on FRR nhrpd. It controls IPSEC. That's why 'close-action' -parameter in IKE configuration always is set to 'close' and 'dead-peer-detection action' -always is set to 'clear'. +parameter in IKE configuration always is set to 'close' +and 'dead-peer-detection action' always is set to 'clear'. ::: ```{cfgcmd} set vpn ipsec profile \<profile-name\> authentication mode pre-shared-secret @@ -188,6 +190,59 @@ Map IKE group to IPSEC profile ``` +### Protecting against unencrypted traffic leaks + +In DMVPN, the mGRE tunnel and the IPSec SA that protects it are handled +independently: GRE forwarding follows the DMVPN/NHRP routing decisions on its +own and does not depend on IPSec SAs being established. + +Because peers are discovered and IPSec SAs are negotiated on demand, +there are conditions when traffic is routed over the tunnel while there is +no active IPSec security association for a given peer—for example, while +the SA for a newly discovered spoke is still being negotiated, or after an +existing SA has expired. + +Such conditions can be short-lived, but they can also persist for a long time +depending on the state of IPSec. +Whenever they occur, the affected packets may leave the router as +unencrypted GRE. This is an inherent property of running GRE and IPSec +independently and is common to DMVPN implementations in general. + +To close this gap you can add a firewall rule that drops any GRE traffic that is +not protected by an outbound IPSec policy. The `match-none-out` matcher matches +packets leaving the router that did not match any outbound IPSec policy, so +combined with `protocol gre` and `action drop` it discards GRE that would +otherwise leave the router in cleartext: + +```none +set firewall ipv4 output filter rule 10 action 'drop' +set firewall ipv4 output filter rule 10 protocol 'gre' +set firewall ipv4 output filter rule 10 ipsec match-none-out +``` + +:::{note} +This rule must be evaluated before any rule that permits GRE. Give it a low rule +number (here `rule 10`) so that it is placed ahead of any GRE-permitting rules +in the `output` filter. Only GRE that is already protected by IPSec +(i.e., matches an outbound IPSec policy) will then be allowed out. +::: + +:::{note} +Because this rule drops all GRE that is not protected by IPSec, it disables +In that case, refine the rule so that it only matches the DMVPN traffic you want +to protect (for example, by also matching on the tunnel source). +Alternatively, you can explicitly allow traffic of known unencrypted tunnels +by their source or destination addresses, or other criteria. +to protect (for example, by also matching on the tunnel source). +Alternatively, you can explicitly allow traffic of known unencrypted tunnels +by their source or destination addresses, or other criteria. +::: + +- Please refer to the {ref}`firewall-ipv4-configuration` documentation for +details on the `set firewall ipv4 output filter rule <N> ipsec match-none-out` +matcher and other firewall options. + + ## Monitoring ```{opcmd} show ip nhrp cache |
