Add support for WireGuard
Almost full support for WireGuard
admin@server:/> show interface wg0
name : wg0
type : wireguard
index : 10
mtu : 1420
operational status : up
ipv4 addresses : 10.0.0.1/24 (static)
ipv6 addresses : fd00::1/64 (static)
peers : 2
Peer 1:
public key : ROaZyvJc5DzA2XUAAeTj2YlwDsy2w0lr3t+rWj2imAk=
status : UP
endpoint : 192.168.10.2:51821
latest handshake : 2025-12-09T22:51:38+00:00
transfer tx : 1412 bytes
transfer rx : 1324 bytes
Peer 2:
public key : Om9CPLYdK3l93GauKrq5WXo/gbcD+1CeqFpobRLLkB4=
status : UP
endpoint : 2001:db8:3c4d:20::2:51822
latest handshake : 2025-12-09T22:51:38+00:00
transfer tx : 1812 bytes
transfer rx : 428 bytes
in-octets : 1752
out-octets : 3224
admin@server:/>
@@ -244,6 +244,7 @@ CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_BONDING=m
|
||||
CONFIG_DUMMY=m
|
||||
CONFIG_WIREGUARD=m
|
||||
CONFIG_MACVLAN=m
|
||||
CONFIG_MACVTAP=m
|
||||
CONFIG_IPVLAN=m
|
||||
|
||||
@@ -191,6 +191,7 @@ CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_BONDING=m
|
||||
CONFIG_DUMMY=m
|
||||
CONFIG_WIREGUARD=m
|
||||
CONFIG_MACVLAN=m
|
||||
CONFIG_MACVTAP=m
|
||||
CONFIG_IPVLAN=m
|
||||
|
||||
@@ -82,6 +82,7 @@ BR2_PACKAGE_OPENSSH=y
|
||||
BR2_PACKAGE_SOCAT=y
|
||||
BR2_PACKAGE_TCPDUMP=y
|
||||
BR2_PACKAGE_WHOIS=y
|
||||
BR2_PACKAGE_WIREGUARD_TOOLS=y
|
||||
BR2_PACKAGE_BASH_COMPLETION=y
|
||||
BR2_PACKAGE_SUDO=y
|
||||
BR2_PACKAGE_GETENT=y
|
||||
|
||||
@@ -82,6 +82,7 @@ BR2_PACKAGE_OPENSSH=y
|
||||
BR2_PACKAGE_SOCAT=y
|
||||
BR2_PACKAGE_TCPDUMP=y
|
||||
BR2_PACKAGE_WHOIS=y
|
||||
BR2_PACKAGE_WIREGUARD_TOOLS=y
|
||||
BR2_PACKAGE_BASH_COMPLETION=y
|
||||
BR2_PACKAGE_SUDO=y
|
||||
BR2_PACKAGE_GETENT=y
|
||||
|
||||
@@ -102,6 +102,7 @@ BR2_PACKAGE_TCPDUMP=y
|
||||
BR2_PACKAGE_TRACEROUTE=y
|
||||
BR2_PACKAGE_ULOGD=y
|
||||
BR2_PACKAGE_WHOIS=y
|
||||
BR2_PACKAGE_WIREGUARD_TOOLS=y
|
||||
BR2_PACKAGE_BASH_COMPLETION=y
|
||||
BR2_PACKAGE_NEOFETCH=y
|
||||
BR2_PACKAGE_SUDO=y
|
||||
|
||||
@@ -85,6 +85,7 @@ BR2_PACKAGE_OPENSSH=y
|
||||
BR2_PACKAGE_SOCAT=y
|
||||
BR2_PACKAGE_TCPDUMP=y
|
||||
BR2_PACKAGE_WHOIS=y
|
||||
BR2_PACKAGE_WIREGUARD_TOOLS=y
|
||||
BR2_PACKAGE_BASH_COMPLETION=y
|
||||
BR2_PACKAGE_SUDO=y
|
||||
BR2_PACKAGE_KMOD_TOOLS=y
|
||||
|
||||
@@ -98,6 +98,7 @@ BR2_PACKAGE_TCPDUMP=y
|
||||
BR2_PACKAGE_TRACEROUTE=y
|
||||
BR2_PACKAGE_ULOGD=y
|
||||
BR2_PACKAGE_WHOIS=y
|
||||
BR2_PACKAGE_WIREGUARD_TOOLS=y
|
||||
BR2_PACKAGE_BASH_COMPLETION=y
|
||||
BR2_PACKAGE_NEOFETCH=y
|
||||
BR2_PACKAGE_SUDO=y
|
||||
|
||||
@@ -80,6 +80,7 @@ BR2_PACKAGE_OPENSSH=y
|
||||
BR2_PACKAGE_SOCAT=y
|
||||
BR2_PACKAGE_TCPDUMP=y
|
||||
BR2_PACKAGE_WHOIS=y
|
||||
BR2_PACKAGE_WIREGUARD_TOOLS=y
|
||||
BR2_PACKAGE_BASH_COMPLETION=y
|
||||
BR2_PACKAGE_SUDO=y
|
||||
BR2_PACKAGE_GETENT=y
|
||||
|
||||
@@ -19,6 +19,7 @@ All notable changes to the project are documented in this file.
|
||||
>
|
||||
> - WiFi Access Point (AP) mode support with multi-SSID capability
|
||||
> - RIPv2 routing support
|
||||
> - WireGuard support
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -47,6 +48,7 @@ All notable changes to the project are documented in this file.
|
||||
moved to `wifi/station` container. Existing Wi-Fi interfaces will be
|
||||
removed during upgrade (for the rest of the configuration to apply)
|
||||
and you need to reconfigure them again. See [wifi.md](wifi.md) for details
|
||||
- Add support for WireGuard VPN tunnels.
|
||||
|
||||
### Fixes
|
||||
|
||||
|
||||
@@ -0,0 +1,983 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 700 500"
|
||||
version="1.1"
|
||||
id="svg220"
|
||||
sodipodi:docname="vpn-hub-spoke.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview222"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.8885714"
|
||||
inkscape:cx="350.00001"
|
||||
inkscape:cy="225.56733"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1014"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg220" />
|
||||
<defs
|
||||
id="defs40">
|
||||
<linearGradient
|
||||
id="bgGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="100%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#fafbfc;stop-opacity:1"
|
||||
id="stop2" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#f3f4f6;stop-opacity:1"
|
||||
id="stop4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="siteGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#3b82f6;stop-opacity:1"
|
||||
id="stop7" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#2563eb;stop-opacity:1"
|
||||
id="stop9" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="routerGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#ef4444;stop-opacity:1"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#dc2626;stop-opacity:1"
|
||||
id="stop14" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="hubGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#f59e0b;stop-opacity:1"
|
||||
id="stop17" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#d97706;stop-opacity:1"
|
||||
id="stop19" />
|
||||
</linearGradient>
|
||||
<filter
|
||||
id="shadow"
|
||||
x="-0.054666667"
|
||||
y="-0.082"
|
||||
width="1.1093333"
|
||||
height="1.184">
|
||||
<feGaussianBlur
|
||||
in="SourceAlpha"
|
||||
stdDeviation="3"
|
||||
id="feGaussianBlur22" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="2"
|
||||
result="offsetblur"
|
||||
id="feOffset24" />
|
||||
<feComponentTransfer
|
||||
id="feComponentTransfer28">
|
||||
<feFuncA
|
||||
type="linear"
|
||||
slope="0.2"
|
||||
id="feFuncA26" />
|
||||
</feComponentTransfer>
|
||||
<feMerge
|
||||
id="feMerge34">
|
||||
<feMergeNode
|
||||
id="feMergeNode30" />
|
||||
<feMergeNode
|
||||
in="SourceGraphic"
|
||||
id="feMergeNode32" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
<marker
|
||||
id="arrow"
|
||||
markerWidth="8"
|
||||
markerHeight="8"
|
||||
refX="7"
|
||||
refY="4"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M 0,0 V 8 L 8,4 Z"
|
||||
fill="#10b981"
|
||||
id="path37" />
|
||||
</marker>
|
||||
<radialGradient
|
||||
id="cloudGrad"
|
||||
cx="220.99805"
|
||||
cy="209.29596"
|
||||
gradientTransform="matrix(1.3416408,0,0,0.74535599,215.52724,137.78745)"
|
||||
fx="220.99805"
|
||||
fy="209.29596"
|
||||
r="51.988579"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
id="stop22" />
|
||||
<stop
|
||||
offset="70%"
|
||||
style="stop-color:#dbeafe;stop-opacity:1"
|
||||
id="stop24" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#93c5fd;stop-opacity:1"
|
||||
id="stop26" />
|
||||
</radialGradient>
|
||||
<filter
|
||||
id="shadow-7"
|
||||
x="-0.061678832"
|
||||
y="-0.11266667"
|
||||
width="1.1233577"
|
||||
height="1.252">
|
||||
<feGaussianBlur
|
||||
in="SourceAlpha"
|
||||
stdDeviation="3"
|
||||
id="feGaussianBlur29" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="2"
|
||||
result="offsetblur"
|
||||
id="feOffset31" />
|
||||
<feComponentTransfer
|
||||
id="feComponentTransfer35">
|
||||
<feFuncA
|
||||
type="linear"
|
||||
slope="0.2"
|
||||
id="feFuncA33" />
|
||||
</feComponentTransfer>
|
||||
<feMerge
|
||||
id="feMerge41">
|
||||
<feMergeNode
|
||||
id="feMergeNode37" />
|
||||
<feMergeNode
|
||||
in="SourceGraphic"
|
||||
id="feMergeNode39" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
<style
|
||||
id="style26">
|
||||
@media (prefers-color-scheme: dark) {
|
||||
#bgGrad stop:first-child { stop-color: #1f2937; }
|
||||
#bgGrad stop:last-child { stop-color: #111827; }
|
||||
#siteGrad stop:first-child { stop-color: #2563eb; }
|
||||
#siteGrad stop:last-child { stop-color: #1e40af; }
|
||||
#routerGrad stop:first-child { stop-color: #dc2626; }
|
||||
#routerGrad stop:last-child { stop-color: #b91c1c; }
|
||||
#hubGrad stop:first-child { stop-color: #f59e0b; }
|
||||
#hubGrad stop:last-child { stop-color: #d97706; }
|
||||
rect[fill="#fff"], rect[fill="#ffffff"] { fill: #374151; }
|
||||
rect[stroke="#e5e7eb"] { stroke: #4b5563; }
|
||||
text[fill="#6b7280"] { fill: #d1d5db; }
|
||||
circle[fill="#60a5fa"] { fill: #3b82f6; }
|
||||
line[stroke="#94a3b8"] { stroke: #6b7280; }
|
||||
rect[fill="#fbbf24"] { fill: #f59e0b; }
|
||||
rect[fill="#fca5a5"] { fill: #fca5a5; }
|
||||
}
|
||||
</style>
|
||||
<!-- Physical Internet connections (solid lines) -->
|
||||
<!-- VPN Tunnels -->
|
||||
<line
|
||||
x1="149.87024"
|
||||
y1="94.852066"
|
||||
x2="262.66898"
|
||||
y2="194.88768"
|
||||
stroke="#10b981"
|
||||
stroke-width="2.6"
|
||||
stroke-dasharray="10,6"
|
||||
marker-end="url(#arrow)"
|
||||
id="line44" />
|
||||
<g
|
||||
transform="translate(155,83)"
|
||||
id="g52">
|
||||
<rect
|
||||
width="8"
|
||||
height="10"
|
||||
rx="1.5"
|
||||
fill="#10b981"
|
||||
id="rect46"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.2"
|
||||
id="path48" />
|
||||
<circle
|
||||
cx="4"
|
||||
cy="6"
|
||||
r="1.2"
|
||||
fill="#ffffff"
|
||||
id="circle50" />
|
||||
</g>
|
||||
<line
|
||||
x1="550.13788"
|
||||
y1="94.850327"
|
||||
x2="437.03882"
|
||||
y2="193.65047"
|
||||
stroke="#10b981"
|
||||
stroke-width="2.6"
|
||||
stroke-dasharray="10,6"
|
||||
marker-end="url(#arrow)"
|
||||
id="line54" />
|
||||
<g
|
||||
transform="translate(537,83)"
|
||||
id="g62">
|
||||
<rect
|
||||
width="8"
|
||||
height="10"
|
||||
rx="1.5"
|
||||
fill="#10b981"
|
||||
id="rect56"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.2"
|
||||
id="path58" />
|
||||
<circle
|
||||
cx="4"
|
||||
cy="6"
|
||||
r="1.2"
|
||||
fill="#ffffff"
|
||||
id="circle60" />
|
||||
</g>
|
||||
<line
|
||||
x1="348.10764"
|
||||
y1="399.8786"
|
||||
x2="348.10764"
|
||||
y2="311.25961"
|
||||
stroke="#10b981"
|
||||
stroke-width="2.6"
|
||||
stroke-dasharray="10, 6"
|
||||
marker-end="url(#arrow)"
|
||||
id="line64" />
|
||||
<g
|
||||
transform="translate(346,383)"
|
||||
id="g72">
|
||||
<rect
|
||||
width="8"
|
||||
height="10"
|
||||
rx="1.5"
|
||||
fill="#10b981"
|
||||
id="rect66"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.2"
|
||||
id="path68" />
|
||||
<circle
|
||||
cx="4"
|
||||
cy="6"
|
||||
r="1.2"
|
||||
fill="#ffffff"
|
||||
id="circle70" />
|
||||
</g>
|
||||
<!-- Hub (Center) -->
|
||||
<g
|
||||
filter="url(#shadow)"
|
||||
id="g114">
|
||||
<rect
|
||||
x="260"
|
||||
y="195"
|
||||
width="180"
|
||||
height="110"
|
||||
rx="12"
|
||||
fill="#fff"
|
||||
stroke="#e5e7eb"
|
||||
stroke-width="2"
|
||||
id="rect82" />
|
||||
<!-- Header -->
|
||||
<rect
|
||||
x="260"
|
||||
y="195"
|
||||
width="180"
|
||||
height="38"
|
||||
rx="12"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect84" />
|
||||
<rect
|
||||
x="260"
|
||||
y="220"
|
||||
width="180"
|
||||
height="13"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect86" />
|
||||
<text
|
||||
x="350"
|
||||
y="220"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="15"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text88">Headquarters</text>
|
||||
<!-- Hub Router -->
|
||||
<rect
|
||||
x="278"
|
||||
y="243"
|
||||
width="144"
|
||||
height="38"
|
||||
rx="8"
|
||||
fill="url(#hubGrad)"
|
||||
id="rect90" />
|
||||
<rect
|
||||
x="280"
|
||||
y="245"
|
||||
width="140"
|
||||
height="18"
|
||||
rx="6"
|
||||
fill="#fbbf24"
|
||||
opacity="0.3"
|
||||
id="rect92" />
|
||||
<text
|
||||
x="350"
|
||||
y="267"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="13"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text94">HUB</text>
|
||||
<!-- Local Network -->
|
||||
<line
|
||||
x1="260"
|
||||
y1="250"
|
||||
x2="180"
|
||||
y2="250"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line96" />
|
||||
<line
|
||||
x1="180"
|
||||
y1="220"
|
||||
x2="180"
|
||||
y2="280"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line98" />
|
||||
<circle
|
||||
cx="172"
|
||||
cy="225"
|
||||
r="5"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle100" />
|
||||
<line
|
||||
x1="180"
|
||||
y1="225"
|
||||
x2="174"
|
||||
y2="225"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line102" />
|
||||
<circle
|
||||
cx="172"
|
||||
cy="250"
|
||||
r="5"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle104" />
|
||||
<line
|
||||
x1="180"
|
||||
y1="250"
|
||||
x2="174"
|
||||
y2="250"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line106" />
|
||||
<circle
|
||||
cx="172"
|
||||
cy="275"
|
||||
r="5"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle108" />
|
||||
<line
|
||||
x1="180"
|
||||
y1="275"
|
||||
x2="174"
|
||||
y2="275"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line110" />
|
||||
<text
|
||||
x="130"
|
||||
y="252"
|
||||
text-anchor="middle"
|
||||
font-family="'SF Mono', 'Monaco', monospace"
|
||||
font-size="8"
|
||||
font-weight="600"
|
||||
fill="#6b7280"
|
||||
id="text112">192.168.0.0/24</text>
|
||||
</g>
|
||||
<!-- Spoke A (Top Left) -->
|
||||
<g
|
||||
filter="url(#shadow)"
|
||||
id="g148">
|
||||
<rect
|
||||
x="40"
|
||||
y="30"
|
||||
width="150"
|
||||
height="100"
|
||||
rx="12"
|
||||
fill="#fff"
|
||||
stroke="#e5e7eb"
|
||||
stroke-width="2"
|
||||
id="rect116" />
|
||||
<!-- Header -->
|
||||
<rect
|
||||
x="40"
|
||||
y="30"
|
||||
width="150"
|
||||
height="32"
|
||||
rx="12"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect118" />
|
||||
<rect
|
||||
x="40"
|
||||
y="51"
|
||||
width="150"
|
||||
height="11"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect120" />
|
||||
<text
|
||||
x="115"
|
||||
y="51"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="14"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text122">Branch A</text>
|
||||
<!-- Router -->
|
||||
<rect
|
||||
x="55"
|
||||
y="70"
|
||||
width="120"
|
||||
height="30"
|
||||
rx="6"
|
||||
fill="url(#routerGrad)"
|
||||
id="rect124" />
|
||||
<rect
|
||||
x="57"
|
||||
y="72"
|
||||
width="116"
|
||||
height="14"
|
||||
rx="4"
|
||||
fill="#fca5a5"
|
||||
opacity="0.3"
|
||||
id="rect126" />
|
||||
<text
|
||||
x="115"
|
||||
y="89"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="11"
|
||||
font-weight="600"
|
||||
fill="#fff"
|
||||
id="text128">Spoke</text>
|
||||
<!-- Local Network -->
|
||||
<line
|
||||
x1="115"
|
||||
y1="100"
|
||||
x2="115"
|
||||
y2="107"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line130" />
|
||||
<line
|
||||
x1="90"
|
||||
y1="107"
|
||||
x2="140"
|
||||
y2="107"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line132" />
|
||||
<circle
|
||||
cx="95"
|
||||
cy="115"
|
||||
r="4"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle134" />
|
||||
<line
|
||||
x1="95"
|
||||
y1="107"
|
||||
x2="95"
|
||||
y2="113"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line136" />
|
||||
<circle
|
||||
cx="115"
|
||||
cy="115"
|
||||
r="4"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle138" />
|
||||
<line
|
||||
x1="115"
|
||||
y1="107"
|
||||
x2="115"
|
||||
y2="113"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line140" />
|
||||
<circle
|
||||
cx="135"
|
||||
cy="115"
|
||||
r="4"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle142" />
|
||||
<line
|
||||
x1="135"
|
||||
y1="107"
|
||||
x2="135"
|
||||
y2="113"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line144" />
|
||||
<text
|
||||
x="115"
|
||||
y="128"
|
||||
text-anchor="middle"
|
||||
font-family="'SF Mono', 'Monaco', monospace"
|
||||
font-size="7"
|
||||
font-weight="600"
|
||||
fill="#6b7280"
|
||||
id="text146">192.168.1.0/24</text>
|
||||
</g>
|
||||
<!-- Spoke B (Top Right) -->
|
||||
<g
|
||||
filter="url(#shadow)"
|
||||
id="g182">
|
||||
<rect
|
||||
x="510"
|
||||
y="30"
|
||||
width="150"
|
||||
height="100"
|
||||
rx="12"
|
||||
fill="#fff"
|
||||
stroke="#e5e7eb"
|
||||
stroke-width="2"
|
||||
id="rect150" />
|
||||
<!-- Header -->
|
||||
<rect
|
||||
x="510"
|
||||
y="30"
|
||||
width="150"
|
||||
height="32"
|
||||
rx="12"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect152" />
|
||||
<rect
|
||||
x="510"
|
||||
y="51"
|
||||
width="150"
|
||||
height="11"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect154" />
|
||||
<text
|
||||
x="585"
|
||||
y="51"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="14"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text156">Branch B</text>
|
||||
<!-- Router -->
|
||||
<rect
|
||||
x="525"
|
||||
y="70"
|
||||
width="120"
|
||||
height="30"
|
||||
rx="6"
|
||||
fill="url(#routerGrad)"
|
||||
id="rect158" />
|
||||
<rect
|
||||
x="527"
|
||||
y="72"
|
||||
width="116"
|
||||
height="14"
|
||||
rx="4"
|
||||
fill="#fca5a5"
|
||||
opacity="0.3"
|
||||
id="rect160" />
|
||||
<text
|
||||
x="585"
|
||||
y="89"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="11"
|
||||
font-weight="600"
|
||||
fill="#fff"
|
||||
id="text162">Spoke</text>
|
||||
<!-- Local Network -->
|
||||
<line
|
||||
x1="585"
|
||||
y1="100"
|
||||
x2="585"
|
||||
y2="107"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line164" />
|
||||
<line
|
||||
x1="560"
|
||||
y1="107"
|
||||
x2="610"
|
||||
y2="107"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line166" />
|
||||
<circle
|
||||
cx="565"
|
||||
cy="115"
|
||||
r="4"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle168" />
|
||||
<line
|
||||
x1="565"
|
||||
y1="107"
|
||||
x2="565"
|
||||
y2="113"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line170" />
|
||||
<circle
|
||||
cx="585"
|
||||
cy="115"
|
||||
r="4"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle172" />
|
||||
<line
|
||||
x1="585"
|
||||
y1="107"
|
||||
x2="585"
|
||||
y2="113"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line174" />
|
||||
<circle
|
||||
cx="605"
|
||||
cy="115"
|
||||
r="4"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle176" />
|
||||
<line
|
||||
x1="605"
|
||||
y1="107"
|
||||
x2="605"
|
||||
y2="113"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line178" />
|
||||
<text
|
||||
x="585"
|
||||
y="125"
|
||||
text-anchor="middle"
|
||||
font-family="'SF Mono', 'Monaco', monospace"
|
||||
font-size="7"
|
||||
font-weight="600"
|
||||
fill="#6b7280"
|
||||
id="text180">192.168.2.0/24</text>
|
||||
</g>
|
||||
<!-- Spoke C (Bottom) -->
|
||||
<g
|
||||
filter="url(#shadow)"
|
||||
id="g216">
|
||||
<rect
|
||||
x="275"
|
||||
y="370"
|
||||
width="150"
|
||||
height="100"
|
||||
rx="12"
|
||||
fill="#fff"
|
||||
stroke="#e5e7eb"
|
||||
stroke-width="2"
|
||||
id="rect184" />
|
||||
<!-- Header -->
|
||||
<rect
|
||||
x="275"
|
||||
y="370"
|
||||
width="150"
|
||||
height="32"
|
||||
rx="12"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect186" />
|
||||
<rect
|
||||
x="275"
|
||||
y="391"
|
||||
width="150"
|
||||
height="11"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect188" />
|
||||
<text
|
||||
x="350"
|
||||
y="391"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="14"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text190">Branch C</text>
|
||||
<!-- Router -->
|
||||
<rect
|
||||
x="290"
|
||||
y="410"
|
||||
width="120"
|
||||
height="30"
|
||||
rx="6"
|
||||
fill="url(#routerGrad)"
|
||||
id="rect192" />
|
||||
<rect
|
||||
x="292"
|
||||
y="412"
|
||||
width="116"
|
||||
height="14"
|
||||
rx="4"
|
||||
fill="#fca5a5"
|
||||
opacity="0.3"
|
||||
id="rect194" />
|
||||
<text
|
||||
x="350"
|
||||
y="429"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="11"
|
||||
font-weight="600"
|
||||
fill="#fff"
|
||||
id="text196">Spoke</text>
|
||||
<!-- Local Network -->
|
||||
<line
|
||||
x1="350"
|
||||
y1="440"
|
||||
x2="350"
|
||||
y2="447"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line198" />
|
||||
<line
|
||||
x1="325"
|
||||
y1="447"
|
||||
x2="375"
|
||||
y2="447"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line200" />
|
||||
<circle
|
||||
cx="330"
|
||||
cy="455"
|
||||
r="4"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle202" />
|
||||
<line
|
||||
x1="330"
|
||||
y1="447"
|
||||
x2="330"
|
||||
y2="453"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line204" />
|
||||
<circle
|
||||
cx="350"
|
||||
cy="455"
|
||||
r="4"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle206" />
|
||||
<line
|
||||
x1="350"
|
||||
y1="447"
|
||||
x2="350"
|
||||
y2="453"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line208" />
|
||||
<circle
|
||||
cx="370"
|
||||
cy="455"
|
||||
r="4"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle210" />
|
||||
<line
|
||||
x1="370"
|
||||
y1="447"
|
||||
x2="370"
|
||||
y2="453"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line212" />
|
||||
<text
|
||||
x="350"
|
||||
y="465"
|
||||
text-anchor="middle"
|
||||
font-family="'SF Mono', 'Monaco', monospace"
|
||||
font-size="7"
|
||||
font-weight="600"
|
||||
fill="#6b7280"
|
||||
id="text214">192.168.3.0/24</text>
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.98466939,0,0,1.0000859,498.17175,113.77759)"
|
||||
id="g97">
|
||||
<rect
|
||||
width="10"
|
||||
height="12"
|
||||
rx="2"
|
||||
fill="#10b981"
|
||||
id="rect91"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.5"
|
||||
id="path93" />
|
||||
<circle
|
||||
cx="5"
|
||||
cy="7"
|
||||
r="1.5"
|
||||
fill="#ffffff"
|
||||
id="circle95" />
|
||||
</g>
|
||||
<text
|
||||
x="446.42084"
|
||||
y="148.79063"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', sans-serif"
|
||||
font-size="10.9158px"
|
||||
font-weight="600"
|
||||
fill="#059669"
|
||||
id="text99"
|
||||
transform="scale(0.99226244,1.0077979)"
|
||||
style="stroke-width:0.992348">Encrypted VPN</text>
|
||||
<g
|
||||
transform="matrix(0.98466939,0,0,1.0000859,193.71492,114.69643)"
|
||||
id="g97-3">
|
||||
<rect
|
||||
width="10"
|
||||
height="12"
|
||||
rx="2"
|
||||
fill="#10b981"
|
||||
id="rect91-6"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.5"
|
||||
id="path93-7" />
|
||||
<circle
|
||||
cx="5"
|
||||
cy="7"
|
||||
r="1.5"
|
||||
fill="#ffffff"
|
||||
id="circle95-5" />
|
||||
</g>
|
||||
<text
|
||||
x="254.16939"
|
||||
y="144.61209"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', sans-serif"
|
||||
font-size="10.9158px"
|
||||
font-weight="600"
|
||||
fill="#059669"
|
||||
id="text99-3"
|
||||
transform="scale(0.99226244,1.0077979)"
|
||||
style="stroke-width:0.992348">Encrypted VPN</text>
|
||||
<g
|
||||
transform="matrix(0.98466939,0,0,1.0000859,333.47081,353.92815)"
|
||||
id="g97-5">
|
||||
<rect
|
||||
width="10"
|
||||
height="12"
|
||||
rx="2"
|
||||
fill="#10b981"
|
||||
id="rect91-62"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.5"
|
||||
id="path93-9" />
|
||||
<circle
|
||||
cx="5"
|
||||
cy="7"
|
||||
r="1.5"
|
||||
fill="#ffffff"
|
||||
id="circle95-1" />
|
||||
</g>
|
||||
<text
|
||||
x="393.52994"
|
||||
y="352.21753"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', sans-serif"
|
||||
font-size="10.9158px"
|
||||
font-weight="600"
|
||||
fill="#059669"
|
||||
id="text99-2"
|
||||
transform="scale(0.99226244,1.0077979)"
|
||||
style="stroke-width:0.992348">Encrypted VPN</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,689 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 700 350"
|
||||
version="1.1"
|
||||
id="svg171"
|
||||
sodipodi:docname="vpn-roadwarrior.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview173"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.8885714"
|
||||
inkscape:cx="350.00001"
|
||||
inkscape:cy="174.73525"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1374"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg171" />
|
||||
<defs
|
||||
id="defs47">
|
||||
<linearGradient
|
||||
id="bgGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="100%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#fafbfc;stop-opacity:1"
|
||||
id="stop2" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#f3f4f6;stop-opacity:1"
|
||||
id="stop4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="corpGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#3b82f6;stop-opacity:1"
|
||||
id="stop7" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#2563eb;stop-opacity:1"
|
||||
id="stop9" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="routerGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#ef4444;stop-opacity:1"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#dc2626;stop-opacity:1"
|
||||
id="stop14" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="deviceGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#8b5cf6;stop-opacity:1"
|
||||
id="stop17" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#7c3aed;stop-opacity:1"
|
||||
id="stop19" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="cloudGrad"
|
||||
cx="220.99805"
|
||||
cy="209.29596"
|
||||
gradientTransform="scale(1.3416408,0.74535599)"
|
||||
fx="220.99805"
|
||||
fy="209.29596"
|
||||
r="51.98858"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
id="stop22" />
|
||||
<stop
|
||||
offset="70%"
|
||||
style="stop-color:#dbeafe;stop-opacity:1"
|
||||
id="stop24" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#93c5fd;stop-opacity:1"
|
||||
id="stop26" />
|
||||
</radialGradient>
|
||||
<filter
|
||||
id="shadow"
|
||||
x="-0.164"
|
||||
y="-0.11699244"
|
||||
width="1.328"
|
||||
height="1.2563258">
|
||||
<feGaussianBlur
|
||||
in="SourceAlpha"
|
||||
stdDeviation="3"
|
||||
id="feGaussianBlur29" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="2"
|
||||
result="offsetblur"
|
||||
id="feOffset31" />
|
||||
<feComponentTransfer
|
||||
id="feComponentTransfer35">
|
||||
<feFuncA
|
||||
type="linear"
|
||||
slope="0.2"
|
||||
id="feFuncA33" />
|
||||
</feComponentTransfer>
|
||||
<feMerge
|
||||
id="feMerge41">
|
||||
<feMergeNode
|
||||
id="feMergeNode37" />
|
||||
<feMergeNode
|
||||
in="SourceGraphic"
|
||||
id="feMergeNode39" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
<marker
|
||||
id="arrow"
|
||||
markerWidth="8"
|
||||
markerHeight="8"
|
||||
refX="7"
|
||||
refY="4"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M 0,0 V 8 L 8,4 Z"
|
||||
fill="#10b981"
|
||||
id="path44" />
|
||||
</marker>
|
||||
</defs>
|
||||
<style
|
||||
id="style30">
|
||||
@media (prefers-color-scheme: dark) {
|
||||
#bgGrad stop:first-child { stop-color: #1f2937; }
|
||||
#bgGrad stop:last-child { stop-color: #111827; }
|
||||
#corpGrad stop:first-child { stop-color: #2563eb; }
|
||||
#corpGrad stop:last-child { stop-color: #1e40af; }
|
||||
#routerGrad stop:first-child { stop-color: #dc2626; }
|
||||
#routerGrad stop:last-child { stop-color: #b91c1c; }
|
||||
#deviceGrad stop:first-child { stop-color: #4c1d95; }
|
||||
#deviceGrad stop:last-child { stop-color: #3b0764; }
|
||||
#cloudGrad stop:first-child { stop-color: #374151; }
|
||||
#cloudGrad stop:nth-child(2) { stop-color: #1e3a8a; }
|
||||
#cloudGrad stop:last-child { stop-color: #1e40af; }
|
||||
rect[fill="#fff"], rect[fill="#ffffff"] { fill: #374151; }
|
||||
rect[stroke="#e5e7eb"] { stroke: #4b5563; }
|
||||
text[fill="#6b7280"] { fill: #d1d5db; }
|
||||
text[fill="#1e40af"] { fill: #60a5fa; }
|
||||
ellipse[fill="#ffffff"] { fill: #4b5563; }
|
||||
circle[fill="#60a5fa"] { fill: #3b82f6; }
|
||||
line[stroke="#94a3b8"] { stroke: #6b7280; }
|
||||
rect[fill="#1e40af"] { fill: #1e3a8a; }
|
||||
rect[fill="#c4b5fd"] { fill: #8b5cf6; }
|
||||
rect[fill="#ede9fe"] { fill: #2e1065; }
|
||||
text[fill="#5b21b6"] { fill: #9333ea; }
|
||||
circle[stroke="#6d28d9"] { stroke: #4c1d95; }
|
||||
rect[stroke="#6d28d9"] { stroke: #4c1d95; }
|
||||
text[fill="#ef4444"] { fill: #fca5a5; }
|
||||
}
|
||||
</style>
|
||||
<!-- Internet Cloud -->
|
||||
<!-- Physical Internet connections (solid lines) -->
|
||||
<line
|
||||
x1="110"
|
||||
y1="65"
|
||||
x2="230"
|
||||
y2="160"
|
||||
stroke="#6b7280"
|
||||
stroke-width="2"
|
||||
id="inet-laptop" />
|
||||
<text
|
||||
x="137.55841"
|
||||
y="109.12807"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', sans-serif"
|
||||
font-size="9px"
|
||||
font-weight="500"
|
||||
fill="#ef4444"
|
||||
id="text-inet-laptop">Unsecure</text>
|
||||
<line
|
||||
x1="79.384186"
|
||||
y1="185.51099"
|
||||
x2="229.7012"
|
||||
y2="183.32214"
|
||||
stroke="#6b7280"
|
||||
stroke-width="2"
|
||||
id="inet-phone" />
|
||||
<text
|
||||
x="145"
|
||||
y="194"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', sans-serif"
|
||||
font-size="9px"
|
||||
font-weight="500"
|
||||
fill="#ef4444"
|
||||
id="text-inet-phone">Unsecure</text>
|
||||
<line
|
||||
x1="105"
|
||||
y1="292"
|
||||
x2="230"
|
||||
y2="190"
|
||||
stroke="#6b7280"
|
||||
stroke-width="2"
|
||||
id="inet-tablet" />
|
||||
<text
|
||||
x="143.19562"
|
||||
y="243.69884"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', sans-serif"
|
||||
font-size="9px"
|
||||
font-weight="500"
|
||||
fill="#ef4444"
|
||||
id="text-inet-tablet">Unsecure</text>
|
||||
<line
|
||||
x1="513.08228"
|
||||
y1="155.4146"
|
||||
x2="344.54852"
|
||||
y2="156.5854"
|
||||
stroke="#6b7280"
|
||||
stroke-width="1.98644"
|
||||
id="inet-corporate" />
|
||||
<text
|
||||
x="430"
|
||||
y="150"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="9"
|
||||
font-weight="500"
|
||||
fill="#ef4444"
|
||||
id="text-inet-corporate">Unsecure</text>
|
||||
<!-- VPN Tunnels: Three lines from clients that merge into one line to server -->
|
||||
<g
|
||||
transform="matrix(0.98466939,0,0,1.0000859,119.62684,52.989786)"
|
||||
id="g73">
|
||||
<rect
|
||||
width="8"
|
||||
height="10"
|
||||
rx="1.5"
|
||||
fill="#10b981"
|
||||
id="rect67"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.2"
|
||||
id="path69" />
|
||||
<circle
|
||||
cx="4"
|
||||
cy="6"
|
||||
r="1.2"
|
||||
fill="#ffffff"
|
||||
id="circle71" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.98466939,0,0,1.0000859,87.933449,161.99967)"
|
||||
id="g81">
|
||||
<rect
|
||||
width="8"
|
||||
height="10"
|
||||
rx="1.5"
|
||||
fill="#10b981"
|
||||
id="rect75"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.2"
|
||||
id="path77" />
|
||||
<circle
|
||||
cx="4"
|
||||
cy="6"
|
||||
r="1.2"
|
||||
fill="#ffffff"
|
||||
id="circle79" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.98466939,0,0,1.0000859,113.62684,307.00955)"
|
||||
id="g89">
|
||||
<rect
|
||||
width="8"
|
||||
height="10"
|
||||
rx="1.5"
|
||||
fill="#10b981"
|
||||
id="rect83"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.2"
|
||||
id="path85" />
|
||||
<circle
|
||||
cx="4"
|
||||
cy="6"
|
||||
r="1.2"
|
||||
fill="#ffffff"
|
||||
id="circle87" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.98466939,0,0,1.0000859,457.18096,186.99924)"
|
||||
id="g97">
|
||||
<rect
|
||||
width="10"
|
||||
height="12"
|
||||
rx="2"
|
||||
fill="#10b981"
|
||||
id="rect91"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.5"
|
||||
id="path93" />
|
||||
<circle
|
||||
cx="5"
|
||||
cy="7"
|
||||
r="1.5"
|
||||
fill="#ffffff"
|
||||
id="circle95" />
|
||||
</g>
|
||||
<text
|
||||
x="413.23505"
|
||||
y="186.04326"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', sans-serif"
|
||||
font-size="10.9158px"
|
||||
font-weight="600"
|
||||
fill="#059669"
|
||||
id="text99"
|
||||
transform="scale(0.99226244,1.0077979)"
|
||||
style="stroke-width:0.992348">Encrypted VPN</text>
|
||||
<!-- Laptop Device -->
|
||||
<g
|
||||
filter="url(#shadow)"
|
||||
id="g115">
|
||||
<rect
|
||||
x="20"
|
||||
y="30"
|
||||
width="90"
|
||||
height="60"
|
||||
rx="6"
|
||||
fill="url(#deviceGrad)"
|
||||
stroke="#6d28d9"
|
||||
stroke-width="2"
|
||||
id="rect103" />
|
||||
<rect
|
||||
x="26"
|
||||
y="36"
|
||||
width="78"
|
||||
height="46"
|
||||
rx="3"
|
||||
fill="#ede9fe"
|
||||
id="rect105" />
|
||||
<rect
|
||||
x="49"
|
||||
y="82"
|
||||
width="32"
|
||||
height="4"
|
||||
rx="2"
|
||||
fill="url(#deviceGrad)"
|
||||
id="rect107" />
|
||||
<rect
|
||||
x="35"
|
||||
y="86"
|
||||
width="60"
|
||||
height="3"
|
||||
rx="1.5"
|
||||
fill="url(#deviceGrad)"
|
||||
id="rect109" />
|
||||
<text
|
||||
x="65"
|
||||
y="63"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="11"
|
||||
font-weight="600"
|
||||
fill="#5b21b6"
|
||||
id="text111">Laptop</text>
|
||||
<text
|
||||
x="65"
|
||||
y="100"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="9"
|
||||
font-weight="500"
|
||||
fill="#6b7280"
|
||||
id="text113">Remote Worker</text>
|
||||
</g>
|
||||
<!-- Mobile Phone Device -->
|
||||
<g
|
||||
filter="url(#shadow)"
|
||||
id="g127">
|
||||
<rect
|
||||
x="30"
|
||||
y="145"
|
||||
width="50"
|
||||
height="80"
|
||||
rx="6"
|
||||
fill="url(#deviceGrad)"
|
||||
stroke="#6d28d9"
|
||||
stroke-width="2"
|
||||
id="rect117" />
|
||||
<rect
|
||||
x="36"
|
||||
y="153"
|
||||
width="38"
|
||||
height="56"
|
||||
rx="3"
|
||||
fill="#ede9fe"
|
||||
id="rect119" />
|
||||
<circle
|
||||
cx="55"
|
||||
cy="218"
|
||||
r="4"
|
||||
fill="#ede9fe"
|
||||
stroke="#6d28d9"
|
||||
stroke-width="1.5"
|
||||
id="circle121" />
|
||||
<text
|
||||
x="55"
|
||||
y="188"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="10"
|
||||
font-weight="600"
|
||||
fill="#5b21b6"
|
||||
id="text123">Mobile</text>
|
||||
<text
|
||||
x="55"
|
||||
y="240"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="9"
|
||||
font-weight="500"
|
||||
fill="#6b7280"
|
||||
id="text125">On-the-go</text>
|
||||
</g>
|
||||
<!-- Tablet Device -->
|
||||
<g
|
||||
filter="url(#shadow)"
|
||||
id="g139">
|
||||
<rect
|
||||
x="25"
|
||||
y="265"
|
||||
width="80"
|
||||
height="55"
|
||||
rx="5"
|
||||
fill="url(#deviceGrad)"
|
||||
stroke="#6d28d9"
|
||||
stroke-width="2"
|
||||
id="rect129" />
|
||||
<rect
|
||||
x="31"
|
||||
y="271"
|
||||
width="68"
|
||||
height="40"
|
||||
rx="3"
|
||||
fill="#ede9fe"
|
||||
id="rect131" />
|
||||
<circle
|
||||
cx="65"
|
||||
cy="313"
|
||||
r="3.5"
|
||||
fill="#ede9fe"
|
||||
stroke="#6d28d9"
|
||||
stroke-width="1.5"
|
||||
id="circle133" />
|
||||
<text
|
||||
x="65"
|
||||
y="295"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="10"
|
||||
font-weight="600"
|
||||
fill="#5b21b6"
|
||||
id="text135">Tablet</text>
|
||||
<text
|
||||
x="65"
|
||||
y="335"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="9"
|
||||
font-weight="500"
|
||||
fill="#6b7280"
|
||||
id="text137">Traveling</text>
|
||||
</g>
|
||||
<!-- Corporate Network -->
|
||||
<g
|
||||
filter="url(#shadow)"
|
||||
id="g167">
|
||||
<rect
|
||||
x="510"
|
||||
y="80"
|
||||
width="170"
|
||||
height="190"
|
||||
rx="12"
|
||||
fill="#fff"
|
||||
stroke="#e5e7eb"
|
||||
stroke-width="2"
|
||||
id="rect141" />
|
||||
<!-- Header -->
|
||||
<rect
|
||||
x="510"
|
||||
y="80"
|
||||
width="170"
|
||||
height="45"
|
||||
rx="12"
|
||||
fill="url(#corpGrad)"
|
||||
id="rect143" />
|
||||
<rect
|
||||
x="510"
|
||||
y="105"
|
||||
width="170"
|
||||
height="20"
|
||||
fill="url(#corpGrad)"
|
||||
id="rect145" />
|
||||
<text
|
||||
x="595"
|
||||
y="108"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="16"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text147">Corporate</text>
|
||||
<rect
|
||||
x="545"
|
||||
y="115"
|
||||
width="100"
|
||||
height="18"
|
||||
rx="9"
|
||||
fill="#1e40af"
|
||||
id="rect149" />
|
||||
<text
|
||||
x="595"
|
||||
y="127"
|
||||
text-anchor="middle"
|
||||
font-family="'SF Mono', 'Monaco', monospace"
|
||||
font-size="11"
|
||||
font-weight="600"
|
||||
fill="#fff"
|
||||
id="text151">192.168.0.0/24</text>
|
||||
<!-- VPN Gateway -->
|
||||
<rect
|
||||
x="530"
|
||||
y="140"
|
||||
width="130"
|
||||
height="42"
|
||||
rx="8"
|
||||
fill="url(#routerGrad)"
|
||||
id="rect153" />
|
||||
<rect
|
||||
x="532"
|
||||
y="142"
|
||||
width="126"
|
||||
height="20"
|
||||
rx="6"
|
||||
fill="#fca5a5"
|
||||
opacity="0.3"
|
||||
id="rect155" />
|
||||
<text
|
||||
x="595"
|
||||
y="165"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="13"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text157">VPN Gateway</text>
|
||||
<!-- Resources -->
|
||||
<rect
|
||||
x="530"
|
||||
y="195"
|
||||
width="130"
|
||||
height="60"
|
||||
rx="8"
|
||||
fill="#dbeafe"
|
||||
stroke="#3b82f6"
|
||||
stroke-width="1.5"
|
||||
id="rect159" />
|
||||
<text
|
||||
x="595"
|
||||
y="218"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="12"
|
||||
font-weight="600"
|
||||
fill="#1e40af"
|
||||
id="text161">Servers</text>
|
||||
<text
|
||||
x="595"
|
||||
y="232"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="12"
|
||||
font-weight="600"
|
||||
fill="#1e40af"
|
||||
id="text163">Files</text>
|
||||
<text
|
||||
x="595"
|
||||
y="246"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="12"
|
||||
font-weight="600"
|
||||
fill="#1e40af"
|
||||
id="text165">Applications</text>
|
||||
</g>
|
||||
<path
|
||||
d="m 230,175 c 0,-13 8,-23 20,-23 2,-9 10,-15 20,-15 7,0 13,3 17,8 5,-7 13,-11 23,-11 16,0 30,11 32,26 13,1 23,12 23,25 0,13 -11,24 -25,24 h -88 c -13,0 -24,-11 -24,-24 0,-7 3,-13 7,-17 z"
|
||||
fill="url(#cloudGrad)"
|
||||
stroke="#3b82f6"
|
||||
stroke-width="2.5"
|
||||
stroke-linejoin="round"
|
||||
id="path51"
|
||||
style="fill:url(#cloudGrad);filter:url(#shadow)" />
|
||||
<line
|
||||
x1="114.70349"
|
||||
y1="64.990814"
|
||||
x2="316.56073"
|
||||
y2="175.00027"
|
||||
stroke="#10b981"
|
||||
stroke-width="2.6"
|
||||
stroke-dasharray="10,6"
|
||||
id="line59" />
|
||||
<line
|
||||
x1="83.621422"
|
||||
y1="175.41223"
|
||||
x2="316.59158"
|
||||
y2="175.58884"
|
||||
stroke="#10b981"
|
||||
stroke-width="2.6"
|
||||
stroke-dasharray="10, 6"
|
||||
id="line61" />
|
||||
<line
|
||||
x1="108.29816"
|
||||
y1="302.53445"
|
||||
x2="316.5495"
|
||||
y2="175.04326"
|
||||
stroke="#10b981"
|
||||
stroke-width="2.6"
|
||||
stroke-dasharray="10, 6"
|
||||
id="line63" />
|
||||
<line
|
||||
x1="316.56073"
|
||||
y1="175.00027"
|
||||
x2="503.64789"
|
||||
y2="175.00027"
|
||||
stroke="#10b981"
|
||||
stroke-width="2.6"
|
||||
stroke-dasharray="12,8"
|
||||
marker-end="url(#arrow)"
|
||||
id="line65" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,595 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 800 300"
|
||||
version="1.1"
|
||||
id="svg178"
|
||||
sodipodi:docname="vpn-site-to-site.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview180"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.6525"
|
||||
inkscape:cx="400"
|
||||
inkscape:cy="150.07564"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1374"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg178" />
|
||||
<defs
|
||||
id="defs42">
|
||||
<linearGradient
|
||||
id="bgGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="100%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#fafbfc;stop-opacity:1"
|
||||
id="stop2" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#f3f4f6;stop-opacity:1"
|
||||
id="stop4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="siteGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#3b82f6;stop-opacity:1"
|
||||
id="stop7" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#2563eb;stop-opacity:1"
|
||||
id="stop9" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="routerGrad"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#ef4444;stop-opacity:1"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#dc2626;stop-opacity:1"
|
||||
id="stop14" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="cloudGrad"
|
||||
cx="288.08009"
|
||||
cy="175.75494"
|
||||
gradientTransform="matrix(1.3416408,0,0,0.74535599,-11.528571,2.8295566)"
|
||||
fx="288.08009"
|
||||
fy="175.75494"
|
||||
r="51.98858"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
id="stop17" />
|
||||
<stop
|
||||
offset="70%"
|
||||
style="stop-color:#dbeafe;stop-opacity:1"
|
||||
id="stop19" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#93c5fd;stop-opacity:1"
|
||||
id="stop21" />
|
||||
</radialGradient>
|
||||
<filter
|
||||
id="shadow"
|
||||
x="-0.061678832"
|
||||
y="-0.11266667"
|
||||
width="1.1233577"
|
||||
height="1.252">
|
||||
<feGaussianBlur
|
||||
in="SourceAlpha"
|
||||
stdDeviation="3"
|
||||
id="feGaussianBlur24" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="2"
|
||||
result="offsetblur"
|
||||
id="feOffset26" />
|
||||
<feComponentTransfer
|
||||
id="feComponentTransfer30">
|
||||
<feFuncA
|
||||
type="linear"
|
||||
slope="0.2"
|
||||
id="feFuncA28" />
|
||||
</feComponentTransfer>
|
||||
<feMerge
|
||||
id="feMerge36">
|
||||
<feMergeNode
|
||||
id="feMergeNode32" />
|
||||
<feMergeNode
|
||||
in="SourceGraphic"
|
||||
id="feMergeNode34" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
<marker
|
||||
id="arrow"
|
||||
markerWidth="8"
|
||||
markerHeight="8"
|
||||
refX="7"
|
||||
refY="4"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M 0,0 V 8 L 8,4 Z"
|
||||
fill="#10b981"
|
||||
id="path39" />
|
||||
</marker>
|
||||
</defs>
|
||||
<style
|
||||
id="style27">
|
||||
@media (prefers-color-scheme: dark) {
|
||||
#bgGrad stop:first-child { stop-color: #1f2937; }
|
||||
#bgGrad stop:last-child { stop-color: #111827; }
|
||||
#siteGrad stop:first-child { stop-color: #2563eb; }
|
||||
#siteGrad stop:last-child { stop-color: #1e40af; }
|
||||
#routerGrad stop:first-child { stop-color: #dc2626; }
|
||||
#routerGrad stop:last-child { stop-color: #b91c1c; }
|
||||
#cloudGrad stop:first-child { stop-color: #374151; }
|
||||
#cloudGrad stop:nth-child(2) { stop-color: #1e3a8a; }
|
||||
#cloudGrad stop:last-child { stop-color: #1e40af; }
|
||||
rect[fill="#fff"], rect[fill="#ffffff"] { fill: #374151; }
|
||||
rect[stroke="#e5e7eb"] { stroke: #4b5563; }
|
||||
text[fill="#6b7280"] { fill: #d1d5db; }
|
||||
text[fill="#1e40af"] { fill: #60a5fa; }
|
||||
ellipse[fill="#ffffff"] { fill: #4b5563; }
|
||||
circle[fill="#60a5fa"] { fill: #3b82f6; }
|
||||
line[stroke="#94a3b8"] { stroke: #6b7280; }
|
||||
rect[fill="#1e40af"] { fill: #1e3a8a; }
|
||||
text[fill="#ef4444"] { fill: #fca5a5; }
|
||||
}
|
||||
</style>
|
||||
<!-- Internet Cloud -->
|
||||
<!-- Physical Internet connections (solid lines) -->
|
||||
<line
|
||||
x1="169.96941"
|
||||
y1="150.66559"
|
||||
x2="308.03061"
|
||||
y2="148.83441"
|
||||
stroke="#6b7280"
|
||||
stroke-width="2"
|
||||
id="inet-left" />
|
||||
<text
|
||||
x="240"
|
||||
y="145"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="10"
|
||||
font-weight="500"
|
||||
fill="#ef4444"
|
||||
id="text-inet-left">Unsecure</text>
|
||||
<line
|
||||
x1="630.02637"
|
||||
y1="143.69931"
|
||||
x2="437.97366"
|
||||
y2="143.80069"
|
||||
stroke="#6b7280"
|
||||
stroke-width="2"
|
||||
id="inet-right" />
|
||||
<text
|
||||
x="535"
|
||||
y="138"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="10"
|
||||
font-weight="500"
|
||||
fill="#ef4444"
|
||||
id="text-inet-right">Unsecure</text>
|
||||
<!-- VPN Tunnel through cloud -->
|
||||
<g
|
||||
transform="translate(191.99738,184.62118)"
|
||||
id="g62">
|
||||
<rect
|
||||
width="10"
|
||||
height="12"
|
||||
rx="2"
|
||||
fill="#10b981"
|
||||
id="rect56"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.5"
|
||||
id="path58" />
|
||||
<circle
|
||||
cx="5"
|
||||
cy="7"
|
||||
r="1.5"
|
||||
fill="#ffffff"
|
||||
id="circle60" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(564.75904,184.3387)"
|
||||
id="g70">
|
||||
<rect
|
||||
width="10"
|
||||
height="12"
|
||||
rx="2"
|
||||
fill="#10b981"
|
||||
id="rect64"
|
||||
x="0"
|
||||
y="0" />
|
||||
<path
|
||||
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
stroke-width="1.5"
|
||||
id="path66" />
|
||||
<circle
|
||||
cx="5"
|
||||
cy="7"
|
||||
r="1.5"
|
||||
fill="#ffffff"
|
||||
id="circle68" />
|
||||
</g>
|
||||
<text
|
||||
x="513.77582"
|
||||
y="161.37065"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', sans-serif"
|
||||
font-size="12px"
|
||||
font-weight="600"
|
||||
fill="#059669"
|
||||
id="text72">Encrypted VPN Tunnel</text>
|
||||
<!-- Site A (Left) -->
|
||||
<g
|
||||
filter="url(#shadow)"
|
||||
id="g124">
|
||||
<rect
|
||||
x="20"
|
||||
y="60"
|
||||
width="170"
|
||||
height="180"
|
||||
rx="12"
|
||||
fill="#fff"
|
||||
stroke="#e5e7eb"
|
||||
stroke-width="2"
|
||||
id="rect76" />
|
||||
<!-- Header -->
|
||||
<rect
|
||||
x="20"
|
||||
y="60"
|
||||
width="170"
|
||||
height="45"
|
||||
rx="12"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect78" />
|
||||
<rect
|
||||
x="20"
|
||||
y="85"
|
||||
width="170"
|
||||
height="20"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect80" />
|
||||
<text
|
||||
x="105"
|
||||
y="88"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="16"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text82">Main Office</text>
|
||||
<rect
|
||||
x="55"
|
||||
y="95"
|
||||
width="100"
|
||||
height="18"
|
||||
rx="9"
|
||||
fill="#1e40af"
|
||||
id="rect84" />
|
||||
<text
|
||||
x="105"
|
||||
y="107"
|
||||
text-anchor="middle"
|
||||
font-family="'SF Mono', 'Monaco', monospace"
|
||||
font-size="11"
|
||||
font-weight="600"
|
||||
fill="#fff"
|
||||
id="text86">192.168.1.0/24</text>
|
||||
<!-- Router -->
|
||||
<rect
|
||||
x="40"
|
||||
y="125"
|
||||
width="130"
|
||||
height="45"
|
||||
rx="8"
|
||||
fill="url(#routerGrad)"
|
||||
id="rect88" />
|
||||
<rect
|
||||
x="42"
|
||||
y="127"
|
||||
width="126"
|
||||
height="20"
|
||||
rx="6"
|
||||
fill="#fca5a5"
|
||||
opacity="0.3"
|
||||
id="rect90" />
|
||||
<text
|
||||
x="105"
|
||||
y="152"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="13"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text92">VPN Gateway</text>
|
||||
<!-- Local Network -->
|
||||
<line
|
||||
x1="105"
|
||||
y1="170"
|
||||
x2="105"
|
||||
y2="195"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line94" />
|
||||
<line
|
||||
x1="65"
|
||||
y1="195"
|
||||
x2="145"
|
||||
y2="195"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line96" />
|
||||
<circle
|
||||
cx="70"
|
||||
cy="204"
|
||||
r="5"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle98" />
|
||||
<line
|
||||
x1="70"
|
||||
y1="195"
|
||||
x2="70"
|
||||
y2="202"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line100" />
|
||||
<circle
|
||||
cx="105"
|
||||
cy="204"
|
||||
r="5"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle102" />
|
||||
<line
|
||||
x1="105"
|
||||
y1="195"
|
||||
x2="105"
|
||||
y2="202"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line104" />
|
||||
<circle
|
||||
cx="140"
|
||||
cy="204"
|
||||
r="5"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle106" />
|
||||
<line
|
||||
x1="140"
|
||||
y1="195"
|
||||
x2="140"
|
||||
y2="202"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line108" />
|
||||
<text
|
||||
x="105"
|
||||
y="218"
|
||||
text-anchor="middle"
|
||||
font-family="'SF Mono', 'Monaco', monospace"
|
||||
font-size="8"
|
||||
font-weight="600"
|
||||
fill="#6b7280"
|
||||
id="text122">192.168.1.0/24</text>
|
||||
</g>
|
||||
<!-- Site B (Right) -->
|
||||
<g
|
||||
filter="url(#shadow)"
|
||||
id="g174">
|
||||
<rect
|
||||
x="610"
|
||||
y="60"
|
||||
width="170"
|
||||
height="180"
|
||||
rx="12"
|
||||
fill="#fff"
|
||||
stroke="#e5e7eb"
|
||||
stroke-width="2"
|
||||
id="rect126" />
|
||||
<!-- Header -->
|
||||
<rect
|
||||
x="610"
|
||||
y="60"
|
||||
width="170"
|
||||
height="45"
|
||||
rx="12"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect128" />
|
||||
<rect
|
||||
x="610"
|
||||
y="85"
|
||||
width="170"
|
||||
height="20"
|
||||
fill="url(#siteGrad)"
|
||||
id="rect130" />
|
||||
<text
|
||||
x="695"
|
||||
y="88"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="16"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text132">Branch Office</text>
|
||||
<rect
|
||||
x="645"
|
||||
y="95"
|
||||
width="100"
|
||||
height="18"
|
||||
rx="9"
|
||||
fill="#1e40af"
|
||||
id="rect134" />
|
||||
<text
|
||||
x="695"
|
||||
y="107"
|
||||
text-anchor="middle"
|
||||
font-family="'SF Mono', 'Monaco', monospace"
|
||||
font-size="11"
|
||||
font-weight="600"
|
||||
fill="#fff"
|
||||
id="text136">192.168.2.0/24</text>
|
||||
<!-- Router -->
|
||||
<rect
|
||||
x="630"
|
||||
y="125"
|
||||
width="130"
|
||||
height="45"
|
||||
rx="8"
|
||||
fill="url(#routerGrad)"
|
||||
id="rect138" />
|
||||
<rect
|
||||
x="632"
|
||||
y="127"
|
||||
width="126"
|
||||
height="20"
|
||||
rx="6"
|
||||
fill="#fca5a5"
|
||||
opacity="0.3"
|
||||
id="rect140" />
|
||||
<text
|
||||
x="695"
|
||||
y="152"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, sans-serif"
|
||||
font-size="13"
|
||||
font-weight="700"
|
||||
fill="#fff"
|
||||
id="text142">VPN Gateway</text>
|
||||
<!-- Local Network -->
|
||||
<line
|
||||
x1="695"
|
||||
y1="170"
|
||||
x2="695"
|
||||
y2="195"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line144" />
|
||||
<line
|
||||
x1="655"
|
||||
y1="195"
|
||||
x2="735"
|
||||
y2="195"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1.5"
|
||||
id="line146" />
|
||||
<circle
|
||||
cx="660"
|
||||
cy="204"
|
||||
r="5"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle148" />
|
||||
<line
|
||||
x1="660"
|
||||
y1="195"
|
||||
x2="660"
|
||||
y2="202"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line150" />
|
||||
<circle
|
||||
cx="695"
|
||||
cy="204"
|
||||
r="5"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle152" />
|
||||
<line
|
||||
x1="695"
|
||||
y1="195"
|
||||
x2="695"
|
||||
y2="202"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line154" />
|
||||
<circle
|
||||
cx="730"
|
||||
cy="204"
|
||||
r="5"
|
||||
fill="#60a5fa"
|
||||
stroke="#2563eb"
|
||||
stroke-width="1"
|
||||
id="circle156" />
|
||||
<line
|
||||
x1="730"
|
||||
y1="195"
|
||||
x2="730"
|
||||
y2="202"
|
||||
stroke="#94a3b8"
|
||||
stroke-width="1"
|
||||
id="line158" />
|
||||
<text
|
||||
x="695"
|
||||
y="218"
|
||||
text-anchor="middle"
|
||||
font-family="'SF Mono', 'Monaco', monospace"
|
||||
font-size="8"
|
||||
font-weight="600"
|
||||
fill="#6b7280"
|
||||
id="text172">192.168.2.0/24</text>
|
||||
</g>
|
||||
<path
|
||||
d="m 308.47143,152.82956 c 0,-13 8,-23 20,-23 2,-9 10,-15 20,-15 7,0 13,3 17,8 5,-7 13,-11 23,-11 16,0 30,11 32,26 13,1 23,12 23,25 0,13 -11,24 -25,24 h -88 c -13,0 -24,-11 -24,-24 0,-7 3,-13 7,-17 z"
|
||||
fill="url(#cloudGrad)"
|
||||
stroke="#3b82f6"
|
||||
stroke-width="2.5"
|
||||
stroke-linejoin="round"
|
||||
id="path46"
|
||||
style="fill:url(#cloudGrad);filter:url(#shadow)" />
|
||||
<line
|
||||
x1="188.49466"
|
||||
y1="166.37616"
|
||||
x2="604.93829"
|
||||
y2="166.37616"
|
||||
stroke="#10b981"
|
||||
stroke-width="2.6"
|
||||
stroke-dasharray="12, 8"
|
||||
marker-end="url(#arrow)"
|
||||
id="line54" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,785 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 900 400"
|
||||
version="1.1"
|
||||
id="svg180"
|
||||
sodipodi:docname="wireguard-allowed-ips.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview182"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.3653333"
|
||||
inkscape:cx="297.36329"
|
||||
inkscape:cy="375.00001"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1374"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg180" />
|
||||
<defs
|
||||
id="defs57">
|
||||
<!-- Premium Gradients -->
|
||||
<linearGradient
|
||||
id="bgGradient"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="821.58384"
|
||||
y2="821.58384"
|
||||
gradientTransform="matrix(1.0954451,0,0,0.46357119,-0.66009153,-0.49920384)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#f8f9fa;stop-opacity:1"
|
||||
id="stop2" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#e9ecef;stop-opacity:1"
|
||||
id="stop4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="peerGradient"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#748ffc;stop-opacity:1"
|
||||
id="stop7" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#5c7cfa;stop-opacity:1"
|
||||
id="stop9" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="networkGradient"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#51cf66;stop-opacity:1"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#40c057;stop-opacity:1"
|
||||
id="stop14" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="tunnelGradient"
|
||||
gradientTransform="scale(9.797959,0.10206207)"
|
||||
x1="21.433035"
|
||||
y1="2767.9234"
|
||||
x2="70.42283"
|
||||
y2="2767.9234"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#5c7cfa;stop-opacity:0.8"
|
||||
id="stop17" />
|
||||
<stop
|
||||
offset="50%"
|
||||
style="stop-color:#4c6ef5;stop-opacity:1"
|
||||
id="stop19" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#5c7cfa;stop-opacity:0.8"
|
||||
id="stop21" />
|
||||
</linearGradient>
|
||||
<!-- Premium Filters -->
|
||||
<filter
|
||||
id="cardShadow"
|
||||
x="-0.075714286"
|
||||
y="-0.35333333"
|
||||
width="1.1514286"
|
||||
height="1.84">
|
||||
<feGaussianBlur
|
||||
in="SourceAlpha"
|
||||
stdDeviation="4"
|
||||
id="feGaussianBlur24" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="4"
|
||||
result="offsetblur"
|
||||
id="feOffset26" />
|
||||
<feComponentTransfer
|
||||
id="feComponentTransfer30">
|
||||
<feFuncA
|
||||
type="linear"
|
||||
slope="0.15"
|
||||
id="feFuncA28" />
|
||||
</feComponentTransfer>
|
||||
<feMerge
|
||||
id="feMerge36">
|
||||
<feMergeNode
|
||||
id="feMergeNode32" />
|
||||
<feMergeNode
|
||||
in="SourceGraphic"
|
||||
id="feMergeNode34" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
<filter
|
||||
id="glow"
|
||||
x="-0.015"
|
||||
y="-inf"
|
||||
width="1.03"
|
||||
height="inf">
|
||||
<feGaussianBlur
|
||||
stdDeviation="3"
|
||||
result="coloredBlur"
|
||||
id="feGaussianBlur39" />
|
||||
<feMerge
|
||||
id="feMerge45">
|
||||
<feMergeNode
|
||||
in="coloredBlur"
|
||||
id="feMergeNode41" />
|
||||
<feMergeNode
|
||||
in="SourceGraphic"
|
||||
id="feMergeNode43" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
<marker
|
||||
id="arrowRight"
|
||||
markerWidth="12"
|
||||
markerHeight="12"
|
||||
refX="9"
|
||||
refY="6"
|
||||
orient="auto"
|
||||
markerUnits="strokeWidth">
|
||||
<path
|
||||
d="M 2,2 L 10,6 L 2,10 Z"
|
||||
fill="#4c6ef5"
|
||||
id="path48" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowLeft"
|
||||
markerWidth="12"
|
||||
markerHeight="12"
|
||||
refX="3"
|
||||
refY="6"
|
||||
orient="auto"
|
||||
markerUnits="strokeWidth">
|
||||
<path
|
||||
d="M 10,2 L 2,6 L 10,10 Z"
|
||||
fill="#4c6ef5"
|
||||
id="path51" />
|
||||
</marker>
|
||||
<marker
|
||||
id="keyArrow"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="8"
|
||||
refY="5"
|
||||
orient="auto"
|
||||
markerUnits="strokeWidth">
|
||||
<path
|
||||
d="M 1,1 L 9,5 L 1,9 Z"
|
||||
fill="#ff6b6b"
|
||||
id="path54" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowRight-3"
|
||||
markerWidth="12"
|
||||
markerHeight="12"
|
||||
refX="9"
|
||||
refY="6"
|
||||
orient="auto"
|
||||
markerUnits="strokeWidth">
|
||||
<path
|
||||
d="m 2,2 8,4 -8,4 z"
|
||||
fill="#4c6ef5"
|
||||
id="path48-6" />
|
||||
</marker>
|
||||
</defs>
|
||||
<style>
|
||||
@media (prefers-color-scheme: dark) {
|
||||
/* Gradients */
|
||||
#bgGradient stop:first-child { stop-color: #1f2937; }
|
||||
#bgGradient stop:last-child { stop-color: #111827; }
|
||||
#peerGradient stop:first-child { stop-color: #3b82f6; }
|
||||
#peerGradient stop:last-child { stop-color: #2563eb; }
|
||||
#networkGradient stop:first-child { stop-color: #10b981; }
|
||||
#networkGradient stop:last-child { stop-color: #059669; }
|
||||
#tunnelGradient stop:first-child { stop-color: #3b82f6; stop-opacity: 0.8; }
|
||||
#tunnelGradient stop:nth-child(2) { stop-color: #2563eb; stop-opacity: 1; }
|
||||
#tunnelGradient stop:last-child { stop-color: #3b82f6; stop-opacity: 0.8; }
|
||||
|
||||
/* White backgrounds to dark */
|
||||
rect[fill="white"] { fill: #374151; }
|
||||
|
||||
/* Borders */
|
||||
rect[stroke="#dee2e6"] { stroke: #4b5563; }
|
||||
rect[stroke="#4263eb"] { stroke: #3b82f6; }
|
||||
rect[stroke="#4dabf7"] { stroke: #60a5fa; }
|
||||
rect[stroke="#fa5252"] { stroke: #ef4444; }
|
||||
rect[stroke="#fab005"] { stroke: #f59e0b; }
|
||||
|
||||
/* Background colors */
|
||||
rect[fill="#e7f5ff"] { fill: #1e3a8a; }
|
||||
rect[fill="#fff5f5"] { fill: #7f1d1d; }
|
||||
rect[fill="#fff3bf"] { fill: #78350f; }
|
||||
rect[fill="#ffffff"] { fill: #374151; }
|
||||
|
||||
/* Text colors */
|
||||
text[fill="#364fc7"] { fill: #60a5fa; }
|
||||
text[fill="#2b8a3e"] { fill: #10b981; }
|
||||
text[fill="#868e96"] { fill: #9ca3af; }
|
||||
text[fill="#1971c2"] { fill: #60a5fa; }
|
||||
text[fill="#c92a2a"] { fill: #f87171; }
|
||||
text[fill="#2f9e44"] { fill: #34d399; }
|
||||
text[fill="#495057"] { fill: #d1d5db; }
|
||||
text[fill="#e67700"] { fill: #fbbf24; }
|
||||
text[fill="#fa5252"] { fill: #f87171; }
|
||||
text[fill="#4263eb"] { fill: #60a5fa; }
|
||||
|
||||
/* Arrows and strokes */
|
||||
line[stroke="#4c6ef5"] { stroke: #60a5fa; }
|
||||
path[stroke="#ff6b6b"] { stroke: #f87171; }
|
||||
#arrowRight path { fill: #60a5fa; }
|
||||
#arrowLeft path { fill: #60a5fa; }
|
||||
#arrowRight-3 path { fill: #60a5fa; }
|
||||
#keyArrow path { fill: #f87171; }
|
||||
}
|
||||
</style>
|
||||
<line
|
||||
id="traffic-arrow-right-5"
|
||||
x1="690.22913"
|
||||
y1="168.51242"
|
||||
x2="584.96887"
|
||||
y2="264.0126"
|
||||
stroke="#4c6ef5"
|
||||
stroke-width="2.5"
|
||||
stroke-dasharray="6, 4"
|
||||
marker-end="url(#arrowRight-3)"
|
||||
style="display:inline;marker-end:url(#arrowRight-3);fill:none"
|
||||
inkscape:label="traffic-arrow-right-5" />
|
||||
<!-- Title -->
|
||||
<text
|
||||
id="title"
|
||||
x="450"
|
||||
y="30"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="22"
|
||||
font-weight="800"
|
||||
fill="#364fc7">Understanding WireGuard: Keys & allowed-ips</text>
|
||||
<!-- Peer A (Left Side) -->
|
||||
<g
|
||||
id="peer-a">
|
||||
<!-- Network behind Peer A -->
|
||||
<g
|
||||
id="network-a"
|
||||
filter="url(#cardShadow)">
|
||||
<rect
|
||||
id="network-a-bg"
|
||||
x="30"
|
||||
y="80"
|
||||
width="180"
|
||||
height="90"
|
||||
rx="12"
|
||||
fill="white"
|
||||
stroke="#dee2e6"
|
||||
stroke-width="2" />
|
||||
<rect
|
||||
id="network-a-header-bg"
|
||||
x="30"
|
||||
y="80"
|
||||
width="180"
|
||||
height="30"
|
||||
rx="12"
|
||||
fill="url(#networkGradient)" />
|
||||
<rect
|
||||
id="network-a-header-extension"
|
||||
x="30"
|
||||
y="98"
|
||||
width="180"
|
||||
height="12"
|
||||
fill="url(#networkGradient)" />
|
||||
<text
|
||||
id="network-a-title"
|
||||
x="120"
|
||||
y="98"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="13"
|
||||
font-weight="700"
|
||||
fill="white">Network A</text>
|
||||
<text
|
||||
id="network-a-cidr"
|
||||
x="120"
|
||||
y="130"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="16"
|
||||
font-weight="600"
|
||||
fill="#2b8a3e">192.168.1.0/24</text>
|
||||
<text
|
||||
id="network-a-devices"
|
||||
x="120"
|
||||
y="155"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="10"
|
||||
fill="#868e96">Devices: .1, .2, .3...</text>
|
||||
</g>
|
||||
<!-- WireGuard Peer A -->
|
||||
<g
|
||||
id="wg-peer-a"
|
||||
filter="url(#cardShadow)">
|
||||
<rect
|
||||
id="wg-peer-a-bg"
|
||||
x="30"
|
||||
y="200"
|
||||
width="180"
|
||||
height="170"
|
||||
rx="12"
|
||||
fill="white"
|
||||
stroke="#4263eb"
|
||||
stroke-width="3" />
|
||||
<rect
|
||||
id="wg-peer-a-header-bg"
|
||||
x="30"
|
||||
y="200"
|
||||
width="180"
|
||||
height="35"
|
||||
rx="12"
|
||||
fill="url(#peerGradient)" />
|
||||
<rect
|
||||
id="wg-peer-a-header-extension"
|
||||
x="30"
|
||||
y="221"
|
||||
width="180"
|
||||
height="14"
|
||||
fill="url(#peerGradient)" />
|
||||
<text
|
||||
id="wg-peer-a-title"
|
||||
x="120"
|
||||
y="221"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="15"
|
||||
font-weight="700"
|
||||
fill="white">WireGuard Peer A</text>
|
||||
<!-- Interface IP -->
|
||||
<rect
|
||||
id="wg-peer-a-interface-bg"
|
||||
x="50"
|
||||
y="245"
|
||||
width="140"
|
||||
height="22"
|
||||
rx="6"
|
||||
fill="#e7f5ff"
|
||||
stroke="#4dabf7"
|
||||
stroke-width="1" />
|
||||
<text
|
||||
id="wg-peer-a-interface-text"
|
||||
x="120"
|
||||
y="260"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="11"
|
||||
font-weight="600"
|
||||
fill="#1971c2">wg0: 10.0.0.1/24</text>
|
||||
<!-- Own Keys -->
|
||||
<rect
|
||||
id="wg-peer-a-keys-bg"
|
||||
x="40"
|
||||
y="275"
|
||||
width="160"
|
||||
height="30"
|
||||
rx="6"
|
||||
fill="#fff5f5"
|
||||
stroke="#fa5252"
|
||||
stroke-width="1.5" />
|
||||
<text
|
||||
id="wg-peer-a-private-key"
|
||||
x="120"
|
||||
y="288"
|
||||
text-anchor="middle"
|
||||
font-family="Consolas, Monaco, 'Courier New', monospace"
|
||||
font-size="9px"
|
||||
font-weight="600"
|
||||
fill="#c92a2a">PrivateKey: aaa...=</text>
|
||||
<text
|
||||
id="wg-peer-a-public-key"
|
||||
x="120"
|
||||
y="300"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="9"
|
||||
font-weight="600"
|
||||
fill="#2f9e44">PublicKey: AAA...=</text>
|
||||
<!-- Peer B Config -->
|
||||
<text
|
||||
id="wg-peer-a-peer-config-label"
|
||||
x="120"
|
||||
y="320"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="10"
|
||||
font-weight="700"
|
||||
fill="#495057">[Peer] # Peer B</text>
|
||||
<rect
|
||||
id="wg-peer-a-peer-config-bg"
|
||||
x="40"
|
||||
y="325"
|
||||
width="160"
|
||||
height="38"
|
||||
rx="6"
|
||||
fill="#fff3bf"
|
||||
stroke="#fab005"
|
||||
stroke-width="1.5" />
|
||||
<text
|
||||
id="wg-peer-a-peer-pubkey"
|
||||
x="120"
|
||||
y="338"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="9"
|
||||
font-weight="700"
|
||||
fill="#e67700">PublicKey = BBB...=</text>
|
||||
<text
|
||||
id="wg-peer-a-peer-allowed-ips-1"
|
||||
x="120"
|
||||
y="350"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="9"
|
||||
font-weight="700"
|
||||
fill="#e67700">allowed-ips = 10.0.0.2/32,</text>
|
||||
<text
|
||||
id="wg-peer-a-peer-allowed-ips-2"
|
||||
x="120"
|
||||
y="360"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="9"
|
||||
font-weight="700"
|
||||
fill="#e67700"> 192.168.2.0/24</text>
|
||||
</g>
|
||||
</g>
|
||||
<!-- Peer B (Right Side) -->
|
||||
<g
|
||||
id="peer-b">
|
||||
<!-- Network behind Peer B -->
|
||||
<g
|
||||
id="network-b"
|
||||
filter="url(#cardShadow)">
|
||||
<rect
|
||||
id="network-b-bg"
|
||||
x="690"
|
||||
y="80"
|
||||
width="180"
|
||||
height="90"
|
||||
rx="12"
|
||||
fill="white"
|
||||
stroke="#dee2e6"
|
||||
stroke-width="2" />
|
||||
<rect
|
||||
id="network-b-header-bg"
|
||||
x="690"
|
||||
y="80"
|
||||
width="180"
|
||||
height="30"
|
||||
rx="12"
|
||||
fill="url(#networkGradient)" />
|
||||
<rect
|
||||
id="network-b-header-extension"
|
||||
x="690"
|
||||
y="98"
|
||||
width="180"
|
||||
height="12"
|
||||
fill="url(#networkGradient)" />
|
||||
<text
|
||||
id="network-b-title"
|
||||
x="780"
|
||||
y="98"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="13"
|
||||
font-weight="700"
|
||||
fill="white">Network B</text>
|
||||
<text
|
||||
id="network-b-cidr"
|
||||
x="780"
|
||||
y="130"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="16"
|
||||
font-weight="600"
|
||||
fill="#2b8a3e">192.168.2.0/24</text>
|
||||
<text
|
||||
id="network-b-devices"
|
||||
x="780"
|
||||
y="155"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="10"
|
||||
fill="#868e96">Devices: .1, .2, .3...</text>
|
||||
</g>
|
||||
<!-- WireGuard Peer B -->
|
||||
<g
|
||||
id="wg-peer-b"
|
||||
filter="url(#cardShadow)">
|
||||
<rect
|
||||
id="wg-peer-b-bg"
|
||||
x="690"
|
||||
y="200"
|
||||
width="180"
|
||||
height="170"
|
||||
rx="12"
|
||||
fill="white"
|
||||
stroke="#4263eb"
|
||||
stroke-width="3" />
|
||||
<rect
|
||||
id="wg-peer-b-header-bg"
|
||||
x="690"
|
||||
y="200"
|
||||
width="180"
|
||||
height="35"
|
||||
rx="12"
|
||||
fill="url(#peerGradient)" />
|
||||
<rect
|
||||
id="wg-peer-b-header-extension"
|
||||
x="690"
|
||||
y="221"
|
||||
width="180"
|
||||
height="14"
|
||||
fill="url(#peerGradient)" />
|
||||
<text
|
||||
id="wg-peer-b-title"
|
||||
x="780"
|
||||
y="221"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="15"
|
||||
font-weight="700"
|
||||
fill="white">WireGuard Peer B</text>
|
||||
<!-- Interface IP -->
|
||||
<rect
|
||||
id="wg-peer-b-interface-bg"
|
||||
x="710"
|
||||
y="245"
|
||||
width="140"
|
||||
height="22"
|
||||
rx="6"
|
||||
fill="#e7f5ff"
|
||||
stroke="#4dabf7"
|
||||
stroke-width="1" />
|
||||
<text
|
||||
id="wg-peer-b-interface-text"
|
||||
x="780"
|
||||
y="260"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="11"
|
||||
font-weight="600"
|
||||
fill="#1971c2">wg0: 10.0.0.2/24</text>
|
||||
<!-- Own Keys -->
|
||||
<rect
|
||||
id="wg-peer-b-keys-bg"
|
||||
x="700"
|
||||
y="275"
|
||||
width="160"
|
||||
height="30"
|
||||
rx="6"
|
||||
fill="#fff5f5"
|
||||
stroke="#fa5252"
|
||||
stroke-width="1.5" />
|
||||
<text
|
||||
id="wg-peer-b-private-key"
|
||||
x="780"
|
||||
y="288"
|
||||
text-anchor="middle"
|
||||
font-family="Consolas, Monaco, 'Courier New', monospace"
|
||||
font-size="9px"
|
||||
font-weight="600"
|
||||
fill="#c92a2a">PrivateKey: bbb...=</text>
|
||||
<text
|
||||
id="wg-peer-b-public-key"
|
||||
x="780"
|
||||
y="300"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="9"
|
||||
font-weight="600"
|
||||
fill="#2f9e44">PublicKey: BBB...=</text>
|
||||
<!-- Peer A Config -->
|
||||
<text
|
||||
id="wg-peer-b-peer-config-label"
|
||||
x="780"
|
||||
y="320"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="10"
|
||||
font-weight="700"
|
||||
fill="#495057">[Peer] # Peer A</text>
|
||||
<rect
|
||||
id="wg-peer-b-peer-config-bg"
|
||||
x="700"
|
||||
y="325"
|
||||
width="160"
|
||||
height="38"
|
||||
rx="6"
|
||||
fill="#fff3bf"
|
||||
stroke="#fab005"
|
||||
stroke-width="1.5" />
|
||||
<text
|
||||
id="wg-peer-b-peer-pubkey"
|
||||
x="780"
|
||||
y="338"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="9"
|
||||
font-weight="700"
|
||||
fill="#e67700">PublicKey = AAA...=</text>
|
||||
<text
|
||||
id="wg-peer-b-peer-allowed-ips-1"
|
||||
x="780"
|
||||
y="350"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="9"
|
||||
font-weight="700"
|
||||
fill="#e67700">allowed-ips = 10.0.0.1/32,</text>
|
||||
<text
|
||||
id="wg-peer-b-peer-allowed-ips-2"
|
||||
x="780"
|
||||
y="360"
|
||||
text-anchor="middle"
|
||||
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
|
||||
font-size="9"
|
||||
font-weight="700"
|
||||
fill="#e67700"> 192.168.1.0/24</text>
|
||||
</g>
|
||||
</g>
|
||||
<!-- Key Exchange Arrows -->
|
||||
<path
|
||||
id="key-arrow-a-to-b"
|
||||
d="m 178.05495,298.67711 q 309.54082,10.30088 544.04144,39.14333"
|
||||
stroke="#ff6b6b"
|
||||
stroke-width="2.45742"
|
||||
stroke-dasharray="6, 4"
|
||||
fill="none"
|
||||
marker-end="url(#keyArrow)" />
|
||||
<text
|
||||
id="key-label-a"
|
||||
x="362.67459"
|
||||
y="320.16849"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="10px"
|
||||
font-weight="600"
|
||||
fill="#fa5252">A's public key (AAA...=)</text>
|
||||
<path
|
||||
id="key-arrow-b-to-a"
|
||||
d="M 729.1812,299.9818 Q 415.736,360.0266 178.27753,338.01017"
|
||||
stroke="#ff6b6b"
|
||||
stroke-width="2.4374"
|
||||
stroke-dasharray="6, 4"
|
||||
fill="none"
|
||||
marker-end="url(#keyArrow)" />
|
||||
<text
|
||||
id="key-label-b"
|
||||
x="375.15118"
|
||||
y="360.33688"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="10px"
|
||||
font-weight="600"
|
||||
fill="#fa5252">B's public key (BBB...=)</text>
|
||||
<!-- WireGuard Tunnel -->
|
||||
<g
|
||||
id="tunnel"
|
||||
transform="translate(0.0587404,0.39164733)">
|
||||
<line
|
||||
id="tunnel-glow"
|
||||
x1="210"
|
||||
y1="285"
|
||||
x2="690"
|
||||
y2="285"
|
||||
stroke="#4c6ef5"
|
||||
stroke-width="10"
|
||||
opacity="0.2"
|
||||
filter="url(#glow)" />
|
||||
<line
|
||||
id="tunnel-line"
|
||||
x1="210"
|
||||
y1="285"
|
||||
x2="690"
|
||||
y2="285"
|
||||
stroke="url(#tunnelGradient)"
|
||||
stroke-width="5"
|
||||
style="stroke:url(#tunnelGradient)" />
|
||||
<!-- Tunnel label -->
|
||||
<rect
|
||||
id="tunnel-label-bg"
|
||||
x="380"
|
||||
y="270"
|
||||
width="140"
|
||||
height="30"
|
||||
rx="8"
|
||||
fill="#ffffff"
|
||||
stroke="#4263eb"
|
||||
stroke-width="2"
|
||||
filter="url(#cardShadow)" />
|
||||
<text
|
||||
id="tunnel-label-text"
|
||||
x="450"
|
||||
y="290"
|
||||
text-anchor="middle"
|
||||
font-family="system-ui, '-apple-system', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="12px"
|
||||
font-weight="700"
|
||||
fill="#4263eb">WireGuard Tunnel</text>
|
||||
</g>
|
||||
<!-- Explanation Box -->
|
||||
<!-- Traffic Flow Example -->
|
||||
<g
|
||||
id="traffic-left"
|
||||
transform="matrix(1.0191745,0,0,1.0648706,-3.9974789,-10.979528)">
|
||||
<line
|
||||
id="traffic-arrow-left"
|
||||
x1="210"
|
||||
y1="170"
|
||||
x2="320"
|
||||
y2="260"
|
||||
stroke="#4c6ef5"
|
||||
stroke-width="2.5"
|
||||
stroke-dasharray="6, 4"
|
||||
marker-end="url(#arrowRight)" />
|
||||
<text
|
||||
id="traffic-label-left"
|
||||
x="290"
|
||||
y="215"
|
||||
font-family="system-ui, '-apple-system', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="9px"
|
||||
font-weight="600"
|
||||
fill="#4263eb">to 192.168.2.x</text>
|
||||
</g>
|
||||
<text
|
||||
id="traffic-label-right"
|
||||
x="583.14978"
|
||||
y="201.57195"
|
||||
font-family="system-ui, '-apple-system', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="9px"
|
||||
font-weight="600"
|
||||
fill="#4263eb">to 192.168.1.x</text>
|
||||
<path
|
||||
style="fill:none"
|
||||
d="m 585.61735,261.45164 c -1.59298,2.54412 -1.30788,10.31284 2.71904,6.28562"
|
||||
id="path1111" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,437 @@
|
||||
# WireGuard VPN
|
||||
|
||||
> [!NOTE]
|
||||
> For a general introduction to VPN concepts and deployment models, see
|
||||
> [VPN Configuration](vpn.md).
|
||||
|
||||
WireGuard is a modern, high-performance VPN protocol that uses state-of-the-art
|
||||
cryptography. It is significantly simpler and faster than traditional VPN
|
||||
solutions like IPsec or OpenVPN, while maintaining strong security guarantees.
|
||||
|
||||
Key features of WireGuard:
|
||||
|
||||
- **Simple Configuration:** Minimal settings required compared to IPsec
|
||||
- **High Performance:** Runs in kernel space with efficient cryptography
|
||||
- **Strong Cryptography:** Uses Curve25519, ChaCha20, Poly1305, and BLAKE2
|
||||
- **Roaming Support:** Seamlessly handles endpoint IP address changes
|
||||
- **Dual-Stack:** Supports IPv4 and IPv6 for both tunnel endpoints and traffic
|
||||
|
||||
> [!IMPORTANT]
|
||||
> When issuing `leave` to activate your changes, remember to also save
|
||||
> your settings, `copy running-config startup-config`. See the [CLI
|
||||
> Introduction](cli/introduction.md) for a background.
|
||||
|
||||
## Key Management
|
||||
|
||||
WireGuard uses public-key cryptography similar to SSH. Each WireGuard interface
|
||||
requires a private key, and each peer is identified by its public key.
|
||||
|
||||
**Generate a WireGuard key pair using the `wg` command:**
|
||||
|
||||
```bash
|
||||
admin@example:~$ wg genkey | tee privatekey | wg pubkey > publickey
|
||||
admin@example:~$ cat privatekey
|
||||
aMqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP=
|
||||
admin@example:~$ cat publickey
|
||||
bN1CwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP=
|
||||
```
|
||||
|
||||
This generates a private key, saves it to `privatekey`, derives the public key,
|
||||
and saves it to `publickey`.
|
||||
|
||||
**Import the private key into the keystore:**
|
||||
|
||||
```
|
||||
admin@example:/> configure
|
||||
admin@example:/config/> edit keystore asymmetric-key wg-site-a
|
||||
admin@example:/config/keystore/asymmetric-key/wg-site-a/> set public-key-format x25519-public-key-format
|
||||
admin@example:/config/keystore/asymmetric-key/wg-site-a/> set private-key-format x25519-private-key-format
|
||||
admin@example:/config/keystore/asymmetric-key/wg-site-a/> set public-key bN1CwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP=
|
||||
admin@example:/config/keystore/asymmetric-key/wg-site-a/> set private-key aMqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP=
|
||||
admin@example:/config/keystore/asymmetric-key/wg-site-a/> leave
|
||||
admin@example:/>
|
||||
```
|
||||
|
||||
**Import peer public keys into the truststore:**
|
||||
|
||||
```
|
||||
admin@example:/> configure
|
||||
admin@example:/config/> edit truststore public-key-bag wg-peers public-key peer-b
|
||||
admin@example:/config/truststore/…/peer-b/> set public-key-format x25519-public-key-format
|
||||
admin@example:/config/truststore/…/peer-b/> set public-key PEER_PUBLIC_KEY_HERE
|
||||
admin@example:/config/truststore/…/peer-b/> leave
|
||||
admin@example:/>
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Keep private keys secure! Never share your private key. Only exchange
|
||||
> public keys with peers. Delete the `privatekey` file after importing it
|
||||
> into the keystore.
|
||||
|
||||
## Point-to-Point Configuration
|
||||
|
||||
> [!TIP]
|
||||
> If you name your WireGuard interface `wgN`, where `N` is a number, the
|
||||
> CLI infers the interface type automatically.
|
||||
|
||||
A basic WireGuard tunnel between two sites:
|
||||
|
||||
**Site A configuration:**
|
||||
|
||||
```
|
||||
admin@siteA:/> configure
|
||||
admin@siteA:/config/> edit interface wg0
|
||||
admin@siteA:/config/interface/wg0/> set wireguard listen-port 51820
|
||||
admin@siteA:/config/interface/wg0/> set wireguard private-key wg-site-a
|
||||
admin@siteA:/config/interface/wg0/> set ipv4 address 10.0.0.1 prefix-length 24
|
||||
admin@siteA:/config/interface/wg0/> edit wireguard peer wg-peers peer-b
|
||||
admin@siteA:/config/interface/…/wg-peers/peer/peer-b/> set endpoint 203.0.113.2
|
||||
admin@siteA:/config/interface/…/wg-peers/peer/peer-b/> set endpoint-port 51820
|
||||
admin@siteA:/config/interface/…/wg-peers/peer/peer-b/> set allowed-ips 10.0.0.2/32
|
||||
admin@siteA:/config/interface/…/wg-peers/peer/peer-b/> set persistent-keepalive 25
|
||||
admin@siteA:/config/interface/…/wg-peers/peer/peer-b/> leave
|
||||
admin@siteA:/>
|
||||
```
|
||||
|
||||
**Site B configuration:**
|
||||
|
||||
```
|
||||
admin@siteB:/> configure
|
||||
admin@siteB:/config/> edit interface wg0
|
||||
admin@siteB:/config/interface/wg0/> set wireguard listen-port 51820
|
||||
admin@siteB:/config/interface/wg0/> set wireguard private-key wg-site-b
|
||||
admin@siteB:/config/interface/wg0/> set ipv4 address 10.0.0.2 prefix-length 24
|
||||
admin@siteB:/config/interface/wg0/> edit wireguard peer wg-peers peer-a
|
||||
admin@siteB:/config/interface/…/wg-peers/peer/peer-a/> set endpoint 203.0.113.1
|
||||
admin@siteB:/config/interface/…/wg-peers/peer/peer-a/> set endpoint-port 51820
|
||||
admin@siteB:/config/interface/…/wg-peers/peer/peer-a/> set allowed-ips 10.0.0.1/32
|
||||
admin@siteB:/config/interface/…/wg-peers/peer/peer-a/> set persistent-keepalive 25
|
||||
admin@siteB:/config/interface/…/wg-peers/peer/peer-a/> leave
|
||||
admin@siteB:/>
|
||||
```
|
||||
|
||||
This creates an encrypted tunnel with Site A at 10.0.0.1 and Site B at 10.0.0.2.
|
||||
|
||||
## Understanding Allowed IPs
|
||||
|
||||
The `allowed-ips` setting in WireGuard serves two critical purposes:
|
||||
|
||||
1. **Ingress Filtering:** Only packets with source IPs in the allowed list
|
||||
are accepted from the peer
|
||||
2. **Cryptokey Routing:** Determines which peer receives outbound packets
|
||||
for a given destination
|
||||
|
||||
Think of `allowed-ips` as a combination of firewall rules and routing table.
|
||||
|
||||

|
||||
*Figure: WireGuard key exchange and allowed-ips configuration between two peers*
|
||||
|
||||
For a simple point-to-point tunnel, you typically allow only the peer's
|
||||
tunnel IP address (e.g., `10.0.0.2/32`). For site-to-site VPNs connecting
|
||||
entire networks, include the remote network prefixes:
|
||||
|
||||
```
|
||||
admin@example:/config/interface/…/wg-peers/peer/peer-a/> set allowed-ips 10.0.0.2/32
|
||||
admin@example:/config/interface/…/wg-peers/peer/peer-a/> set allowed-ips 192.168.2.0/24
|
||||
```
|
||||
|
||||
This allows traffic to/from the peer at 10.0.0.2 and routes traffic destined
|
||||
for 192.168.2.0/24 through this peer.
|
||||
|
||||
> [!NOTE]
|
||||
> When routing traffic to networks behind WireGuard peers, you also need
|
||||
> to configure static routes pointing to the WireGuard interface. See
|
||||
> [Static Routes](networking.md#static-routes) for more information.
|
||||
|
||||
## Peer Configuration and Key Bags
|
||||
|
||||
WireGuard peer configuration supports a two-level hierarchy that allows
|
||||
efficient management of multiple peers with shared settings.
|
||||
|
||||
**Public Key Bags** group related peers together (e.g., all mobile clients,
|
||||
all branch offices) and allow you to configure default settings that apply
|
||||
to all peers in the bag. Individual peers can then override these defaults
|
||||
when needed.
|
||||
|
||||
Settings that support bag-level defaults and per-peer overrides:
|
||||
|
||||
- `endpoint` - Remote peer's IP address
|
||||
- `endpoint-port` - Remote peer's UDP port (defaults to 51820 at bag level)
|
||||
- `persistent-keepalive` - Keepalive interval in seconds
|
||||
- `preshared-key` - Optional pre-shared key for additional quantum resistance
|
||||
- `allowed-ips` - IP addresses allowed to/from this peer
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Key Bag Configuration Rules:**
|
||||
> - **Single key in bag:** You can use bag-level settings (endpoint, allowed-ips, etc.)
|
||||
> without specifying individual peer configurations. All settings apply to that one peer.
|
||||
> - **Multiple keys in bag:** You MUST provide individual `peer` configuration for
|
||||
> each key in the bag. Settings like `endpoint` and `allowed-ips` must be unique
|
||||
> per peer and cannot be shared at the bag level when multiple peers exist.
|
||||
>
|
||||
> This prevents configuration errors where multiple peers would incorrectly share
|
||||
> the same endpoint address or allowed-ips ranges.
|
||||
|
||||
**Example with bag-level defaults:**
|
||||
|
||||
```
|
||||
admin@example:/> configure
|
||||
admin@example:/config/> edit interface wg0
|
||||
admin@example:/config/interface/wg0/> set wireguard listen-port 51820
|
||||
admin@example:/config/interface/wg0/> set wireguard private-key wg-key
|
||||
admin@example:/config/interface/wg0/> set ipv4 address 10.0.0.1 prefix-length 24
|
||||
|
||||
# Configure defaults for all peers in the 'branch-offices' bag
|
||||
admin@example:/config/interface/wg0/> edit wireguard peers branch-offices
|
||||
admin@example:/config/interface/…/wireguard/peers/branch-offices/> set endpoint-port 51820
|
||||
admin@example:/config/interface/…/wireguard/peers/branch-offices/> set persistent-keepalive 25
|
||||
admin@example:/config/interface/…/wireguard/peers/branch-offices/> end
|
||||
|
||||
# Configure peer-specific settings (inherits endpoint-port and keepalive from bag)
|
||||
admin@example:/config/interface/…/wireguard/peers/branch-offices/> edit peer office-east
|
||||
admin@example:/config/interface/…/branch-offices/peer/office-east/> set endpoint 203.0.113.10
|
||||
admin@example:/config/interface/…/branch-offices/peer/office-east/> set allowed-ips 10.0.0.10/32
|
||||
admin@example:/config/interface/…/branch-offices/peer/office-east/> set allowed-ips 192.168.10.0/24
|
||||
admin@example:/config/interface/…/branch-offices/peer/office-east/> end
|
||||
|
||||
# Another peer with an override for persistent-keepalive
|
||||
admin@example:/config/interface/…/wireguard/peers/branch-offices/> edit peer office-west
|
||||
admin@example:/config/interface/…/branch-offices/peer/office-west/> set endpoint 203.0.113.20
|
||||
admin@example:/config/interface/…/branch-offices/peer/office-west/> set allowed-ips 10.0.0.20/32
|
||||
admin@example:/config/interface/…/branch-offices/peer/office-west/> set allowed-ips 192.168.20.0/24
|
||||
admin@example:/config/interface/…/branch-offices/peer/office-west/> set persistent-keepalive 10
|
||||
admin@example:/config/interface/…/branch-offices/peer/office-west/> leave
|
||||
admin@example:/>
|
||||
```
|
||||
|
||||
In this example:
|
||||
- Both peers inherit `endpoint-port 51820` and `persistent-keepalive 25` from the bag
|
||||
- `office-west` overrides the keepalive to 10 seconds while `office-east` uses the default 25
|
||||
- Each peer has its own `endpoint` and `allowed-ips` configuration
|
||||
|
||||
This approach simplifies management when you have many peers with similar
|
||||
configurations - set the common defaults once at the bag level, then only
|
||||
specify per-peer differences.
|
||||
|
||||
## Site-to-Site VPN
|
||||
|
||||

|
||||
*Figure: Site-to-Site VPN connecting two office networks*
|
||||
|
||||
A site-to-site VPN connects entire networks across locations, creating a unified
|
||||
private network over the internet. This allows devices in one location to
|
||||
seamlessly access resources in another as if they were on the same local network.
|
||||
|
||||
This is the point-to-point configuration shown earlier, extended with routing
|
||||
to allow access to networks behind each peer. Configure the WireGuard tunnel
|
||||
as shown in [Point-to-Point Configuration](#point-to-point-configuration),
|
||||
then add the remote network to `allowed-ips` and configure static routes.
|
||||
|
||||
## Road Warrior VPN
|
||||
|
||||

|
||||
*Figure: Mobile clients connecting to corporate network*
|
||||
|
||||
For mobile clients or peers without fixed IPs, omit the `endpoint` setting.
|
||||
WireGuard learns the peer's endpoint from authenticated incoming packets:
|
||||
|
||||
```
|
||||
admin@hub:/> configure
|
||||
admin@hub:/config/> edit interface wg0 wireguard peers wg-peers peer mobile-client
|
||||
admin@hub:/config/interface/…/wg-peers/peer/mobile-client/> set allowed-ips 10.0.0.10/32
|
||||
admin@hub:/config/interface/…/wg-peers/peer/mobile-client/> leave
|
||||
admin@hub:/>
|
||||
```
|
||||
|
||||
The mobile client configures the hub's endpoint normally. The hub learns
|
||||
and tracks the mobile client's changing IP address automatically.
|
||||
|
||||
## Hub-and-Spoke Topology
|
||||
|
||||

|
||||
*Figure: Hub-and-Spoke topology with central hub routing traffic between spokes*
|
||||
|
||||
WireGuard excels at hub-and-spoke (star) topologies where multiple remote
|
||||
sites connect to a central hub.
|
||||
|
||||
**Hub configuration:**
|
||||
|
||||
```
|
||||
admin@hub:/> configure
|
||||
admin@hub:/config/> edit interface wg0
|
||||
admin@hub:/config/interface/wg0/> set ipv4 address 10.0.0.1 prefix-length 24
|
||||
admin@hub:/config/interface/wg0/> set wireguard listen-port 51820
|
||||
admin@hub:/config/interface/wg0/> set wireguard private-key wg-hub
|
||||
admin@hub:/config/interface/wg0/> edit wireguard peers wg-peers
|
||||
|
||||
# Spoke 1
|
||||
admin@hub:/config/interface/…/wireguard/peers/wg-peers/> edit peer spoke1
|
||||
admin@hub:/config/interface/…/wg-peers/peer/spoke1/> set allowed-ips 10.0.0.2/32
|
||||
admin@hub:/config/interface/…/wg-peers/peer/spoke1/> set allowed-ips 192.168.1.0/24
|
||||
admin@hub:/config/interface/…/wg-peers/peer/spoke1/> end
|
||||
|
||||
# Spoke 2
|
||||
admin@hub:/config/interface/…/wireguard/peers/wg-peers/> edit peer spoke2
|
||||
admin@hub:/config/interface/…/wg-peers/peer/spoke2/> set allowed-ips 10.0.0.3/32
|
||||
admin@hub:/config/interface/…/wg-peers/peer/spoke2/> set allowed-ips 192.168.2.0/24
|
||||
admin@hub:/config/interface/…/wg-peers/peer/spoke2/> leave
|
||||
|
||||
# Add routes for spoke networks
|
||||
admin@hub:/> configure
|
||||
admin@hub:/config/> edit routing control-plane-protocol static name default
|
||||
admin@hub:/config/routing/…/static/name/default/> set ipv4 route 192.168.1.0/24 wg0
|
||||
admin@hub:/config/routing/…/static/name/default/> set ipv4 route 192.168.2.0/24 wg0
|
||||
admin@hub:/config/routing/…/static/name/default/> leave
|
||||
admin@hub:/>
|
||||
```
|
||||
|
||||
**Spoke 1 configuration:**
|
||||
|
||||
```
|
||||
admin@spoke1:/> configure
|
||||
admin@spoke1:/config/> edit interface wg0
|
||||
admin@spoke1:/config/interface/wg0/> set wireguard listen-port 51820
|
||||
admin@spoke1:/config/interface/wg0/> set wireguard private-key wg-spoke1
|
||||
admin@spoke1:/config/interface/wg0/> set ipv4 address 10.0.0.2 prefix-length 24
|
||||
admin@spoke1:/config/interface/wg0/> edit wireguard peers wg-peers peer hub
|
||||
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> set endpoint 203.0.113.1
|
||||
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> set endpoint-port 51820
|
||||
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> set allowed-ips 10.0.0.1/32
|
||||
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> set allowed-ips 10.0.0.3/32
|
||||
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> set allowed-ips 192.168.0.0/24
|
||||
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> set allowed-ips 192.168.2.0/24
|
||||
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> set persistent-keepalive 25
|
||||
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> leave
|
||||
admin@spoke1:/> configure
|
||||
admin@spoke1:/config/> edit routing control-plane-protocol static name default
|
||||
admin@spoke1:/config/routing/…/static/name/default/> set ipv4 route 192.168.0.0/24 wg0
|
||||
admin@spoke1:/config/routing/…/static/name/default/> set ipv4 route 192.168.2.0/24 wg0
|
||||
admin@spoke1:/config/routing/…/static/name/default/> leave
|
||||
admin@spoke1:/>
|
||||
```
|
||||
|
||||
This configuration allows Spoke 1 to reach both the hub network (192.168.0.0/24)
|
||||
and Spoke 2's network (192.168.2.0/24) via the hub, enabling spoke-to-spoke
|
||||
communication through the central hub.
|
||||
|
||||
## Persistent Keepalive
|
||||
|
||||
The `persistent-keepalive` setting sends periodic packets to keep the tunnel
|
||||
active through NAT devices and firewalls:
|
||||
|
||||
```
|
||||
admin@example:/config/interface/…/wg-peers/peer/hub/> set persistent-keepalive 25
|
||||
```
|
||||
|
||||
This is particularly important when:
|
||||
|
||||
- The peer is behind NAT
|
||||
- Intermediate firewalls have connection timeouts
|
||||
- You need the tunnel to remain ready for bidirectional traffic
|
||||
|
||||
A value of 25 seconds is recommended for most scenarios. Omit this setting
|
||||
for peers with public static IPs that initiate connections.
|
||||
|
||||
> [!NOTE]
|
||||
> Only the peer behind NAT needs `persistent-keepalive` configured. The
|
||||
> peer with a public IP learns the NAT endpoint from incoming packets.
|
||||
|
||||
## IPv6 Endpoints
|
||||
|
||||
WireGuard fully supports IPv6 for tunnel endpoints:
|
||||
|
||||
```
|
||||
admin@example:/> configure
|
||||
admin@example:/config/> edit interface wg0
|
||||
admin@example:/config/interface/wg0/> set wireguard listen-port 51820
|
||||
admin@example:/config/interface/wg0/> set wireguard private-key wg-key
|
||||
admin@example:/config/interface/wg0/> set ipv4 address 10.0.0.1 prefix-length 24
|
||||
admin@example:/config/interface/wg0/> set ipv6 address fd00::1 prefix-length 64
|
||||
admin@example:/config/interface/wg0/> edit wireguard peers wg-peers peer remote
|
||||
admin@example:/config/interface/…/wg-peers/peer/remote/> set endpoint 2001:db8::2
|
||||
admin@example:/config/interface/…/wg-peers/peer/remote/> set endpoint-port 51820
|
||||
admin@example:/config/interface/…/wg-peers/peer/remote/> set allowed-ips 10.0.0.2/32
|
||||
admin@example:/config/interface/…/wg-peers/peer/remote/> set allowed-ips fd00::2/128
|
||||
admin@example:/config/interface/…/wg-peers/peer/remote/> leave
|
||||
admin@example:/>
|
||||
```
|
||||
|
||||
WireGuard can carry both IPv4 and IPv6 traffic regardless of whether the
|
||||
tunnel endpoints use IPv4 or IPv6.
|
||||
|
||||
## Monitoring WireGuard Status
|
||||
|
||||
Check WireGuard interface status and peer connections:
|
||||
|
||||
```
|
||||
admin@example:/> show interfaces
|
||||
wg0 wireguard UP 2 peers (1 up)
|
||||
ipv4 10.0.0.1/24 (static)
|
||||
ipv6 fd00::1/64 (static)
|
||||
|
||||
admin@example:/> show interfaces wg0
|
||||
name : wg0
|
||||
type : wireguard
|
||||
index : 12
|
||||
operational status : up
|
||||
peers : 2
|
||||
|
||||
Peer 1:
|
||||
status : UP
|
||||
endpoint : 203.0.113.2:51820
|
||||
latest handshake : 2025-12-09T10:23:45+0000
|
||||
transfer tx : 125648 bytes
|
||||
transfer rx : 98432 bytes
|
||||
|
||||
Peer 2:
|
||||
status : DOWN
|
||||
endpoint : 203.0.113.3:51820
|
||||
latest handshake : 2025-12-09T09:15:22+0000
|
||||
transfer tx : 45120 bytes
|
||||
transfer rx : 32768 bytes
|
||||
```
|
||||
|
||||
The connection status shows `UP` if a handshake occurred within the last 3
|
||||
minutes, indicating an active tunnel. The `latest handshake` timestamp shows
|
||||
when the peers last successfully authenticated and exchanged keys.
|
||||
|
||||
## Post-Quantum Security (Preshared Keys)
|
||||
|
||||
WireGuard supports optional preshared keys (PSK) that add an extra layer of
|
||||
symmetric encryption alongside Curve25519. This provides defense-in-depth
|
||||
against future quantum computers that might break elliptic curve cryptography.
|
||||
|
||||
PSKs protect your data from "harvest now, decrypt later" attacks - adversaries
|
||||
recording traffic today would still need the PSK even if they break Curve25519
|
||||
later. However, peer authentication still relies on Curve25519, so PSKs don't
|
||||
provide complete post-quantum security.
|
||||
|
||||
**Generate a preshared key using `wg genpsk`:**
|
||||
|
||||
```bash
|
||||
admin@example:~$ wg genpsk > preshared.key
|
||||
admin@example:~$ cat preshared.key
|
||||
cO2DxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2m=
|
||||
```
|
||||
|
||||
**Import the preshared key into the keystore:**
|
||||
|
||||
```
|
||||
admin@example:/> configure
|
||||
admin@example:/config/> edit keystore symmetric-key wg-psk
|
||||
admin@example:/config/keystore/symmetric-key/wg-psk/> set key-format wireguard-symmetric-key-format
|
||||
admin@example:/config/keystore/symmetric-key/wg-psk/> set key cO2DxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2m=
|
||||
admin@example:/config/keystore/symmetric-key/wg-psk/> end
|
||||
admin@example:/config/interface/wg0/> edit wireguard peers wg-peers peer remote
|
||||
admin@example:/config/interface/…/wg-peers/peer/remote/> set preshared-key wg-psk
|
||||
admin@example:/config/interface/…/wg-peers/peer/remote/> leave
|
||||
admin@example:/>
|
||||
```
|
||||
|
||||
The preshared key must be securely shared between both peers and configured
|
||||
on both sides.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Preshared keys must be kept secret and exchanged through a secure channel,
|
||||
> just like passwords. Delete the `preshared.key` file after importing it
|
||||
> into both peer keystores.
|
||||
@@ -0,0 +1,83 @@
|
||||
# VPN Configuration
|
||||
|
||||
A Virtual Private Network (VPN) creates encrypted tunnels over public networks,
|
||||
enabling secure communication between remote locations or users. Unlike plain
|
||||
tunnels (GRE, VXLAN) that only provide encapsulation, VPNs add authentication
|
||||
and encryption to protect data confidentiality and integrity.
|
||||
|
||||
|
||||
## Configuring VPN
|
||||
|
||||
For detailed configuration instructions and examples, see:
|
||||
|
||||
- **[WireGuard VPN](vpn-wireguard.md)** - Complete guide to configuring
|
||||
WireGuard tunnels, including site-to-site, road warrior, and hub-and-spoke
|
||||
topologies.
|
||||
|
||||
## Understanding VPN Tunnels
|
||||
|
||||
VPN tunnels establish secure connections across untrusted networks by:
|
||||
|
||||
- **Authentication:** Verifying the identity of tunnel endpoints using
|
||||
cryptographic keys or certificates
|
||||
- **Encryption:** Protecting data confidentiality with strong ciphers
|
||||
- **Integrity:** Detecting tampering through message authentication codes
|
||||
|
||||
This makes VPNs essential for connecting sites over the internet, enabling
|
||||
remote access for mobile users, and securing traffic in untrusted environments.
|
||||
|
||||
### VPN Deployment Models
|
||||
|
||||
VPNs are typically deployed in one of several models:
|
||||
|
||||
**Site-to-Site VPN**
|
||||
|
||||

|
||||
*Figure: Site-to-Site VPN connecting two office networks*
|
||||
|
||||
Connects entire networks across locations, creating a unified private network
|
||||
over the internet. Routers or firewalls at each site maintain persistent
|
||||
tunnels, allowing seamless access between locations.
|
||||
|
||||
- Use case: Connecting branch offices to headquarters
|
||||
- Characteristics: Always-on, connects networks not individual devices
|
||||
- Example: Main office (192.168.1.0/24) ↔ Branch office (192.168.2.0/24)
|
||||
|
||||
**Remote Access VPN (Road Warrior)**
|
||||
|
||||

|
||||
*Figure: Mobile clients connecting to corporate network*
|
||||
|
||||
Enables individual users to securely access a private network from remote
|
||||
locations. Clients initiate connections as needed from dynamic IP addresses.
|
||||
|
||||
- Use case: Remote employees accessing corporate resources
|
||||
- Characteristics: On-demand, handles dynamic endpoints and roaming
|
||||
- Example: Mobile laptop ↔ Corporate network
|
||||
|
||||
**Hub-and-Spoke VPN**
|
||||
|
||||

|
||||
*Figure: Hub-and-Spoke topology with central hub routing traffic between spokes*
|
||||
|
||||
A central hub connects to multiple remote sites (spokes), routing traffic
|
||||
between them. Spokes don't connect directly to each other but communicate
|
||||
through the hub.
|
||||
|
||||
- Use case: Central office connecting multiple remote locations
|
||||
- Characteristics: Centralized control, simplified management
|
||||
- Example: HQ ↔ (Branch A, Branch B, Branch C)
|
||||
|
||||
### VPN Protocol Comparison
|
||||
|
||||
Different VPN protocols offer varying trade-offs between security, performance,
|
||||
and complexity:
|
||||
|
||||
| Protocol | Complexity | Performance | Use Case |
|
||||
|------------|------------|-------------|---------------------------------|
|
||||
| WireGuard | Simple | Very High | Modern deployments, all models |
|
||||
| IPsec | Complex | High | Legacy systems, compliance reqs |
|
||||
| OpenVPN | Moderate | Moderate | Maximum compatibility |
|
||||
|
||||
Infix supports WireGuard as its primary VPN solution, offering the best
|
||||
balance of simplicity, security, and performance for modern networks.
|
||||
@@ -33,6 +33,7 @@ nav:
|
||||
- Quality of Service: qos.md
|
||||
- RMON Counters: eth-counters.md
|
||||
- Tunneling (L2/L3): tunnels.md
|
||||
- VPN Tunnels: vpn.md
|
||||
- Wireless LAN (WiFi): wifi.md
|
||||
- Services:
|
||||
- Device Discovery: discovery.md
|
||||
|
||||
@@ -38,6 +38,7 @@ confd_plugin_la_SOURCES = \
|
||||
if-gre.c \
|
||||
if-vxlan.c \
|
||||
if-wifi.c \
|
||||
if-wireguard.c \
|
||||
keystore.c \
|
||||
system.c \
|
||||
ntp.c \
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
#include <srx/lyx.h>
|
||||
|
||||
#include "interfaces.h"
|
||||
|
||||
#define WIREGUARD_CONFIG "/run/wireguard-%s.conf"
|
||||
|
||||
/* Helper to get a peer setting with override logic:
|
||||
* 1. Check peer-specific override
|
||||
* 2. Fall back to key-bag level default
|
||||
*/
|
||||
static const char *get_peer_setting(struct lyd_node *peer_override, struct lyd_node *bag_peer,
|
||||
const char *setting_name)
|
||||
{
|
||||
const char *value = NULL;
|
||||
|
||||
if (peer_override)
|
||||
value = lydx_get_cattr(peer_override, setting_name);
|
||||
if (!value)
|
||||
value = lydx_get_cattr(bag_peer, setting_name);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void write_allowed_ips(FILE *wg_fp, struct lyd_node *peer_override, struct lyd_node *bag_peer)
|
||||
{
|
||||
struct lyd_node *settings_node, *allowed_ip, *check_ip;
|
||||
int first = 1;
|
||||
|
||||
/* Determine which node has the allowed-ips to use:
|
||||
* If peer override exists and has any allowed-ips, use those.
|
||||
* Otherwise use bag-level allowed-ips.
|
||||
*/
|
||||
settings_node = bag_peer; /* Default to bag level */
|
||||
if (peer_override && lyd_child(peer_override)) {
|
||||
LYX_LIST_FOR_EACH(lyd_child(peer_override), check_ip, "allowed-ips") {
|
||||
settings_node = peer_override; /* Override has IPs, use them */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LYX_LIST_FOR_EACH(lyd_child(settings_node), allowed_ip, "allowed-ips") {
|
||||
const char *ip_prefix = lyd_get_value(allowed_ip);
|
||||
|
||||
if (ip_prefix) {
|
||||
fprintf(wg_fp, "%s%s", first ? "AllowedIPs = " : ", ", ip_prefix);
|
||||
first = 0;
|
||||
}
|
||||
}
|
||||
if (!first)
|
||||
fprintf(wg_fp, "\n");
|
||||
}
|
||||
|
||||
static void write_peer(FILE *wg_fp, struct lyd_node *cif, struct lyd_node *bag_peer,
|
||||
struct lyd_node *peer_override, const char *public_key_data)
|
||||
{
|
||||
const char *preshared_key_ref, *preshared_key_data;
|
||||
const char *endpoint, *endpoint_port, *keepalive;
|
||||
struct lyd_node *psk_node;
|
||||
|
||||
fprintf(wg_fp, "\n[Peer]\n");
|
||||
fprintf(wg_fp, "PublicKey = %s\n", public_key_data);
|
||||
|
||||
preshared_key_ref = get_peer_setting(peer_override, bag_peer, "preshared-key");
|
||||
endpoint = get_peer_setting(peer_override, bag_peer, "endpoint");
|
||||
endpoint_port = get_peer_setting(peer_override, bag_peer, "endpoint-port");
|
||||
keepalive = get_peer_setting(peer_override, bag_peer, "persistent-keepalive");
|
||||
|
||||
if (preshared_key_ref) {
|
||||
psk_node = lydx_get_xpathf(cif, "../../keystore/symmetric-keys/symmetric-key[name='%s']",
|
||||
preshared_key_ref);
|
||||
if (psk_node) {
|
||||
preshared_key_data = lydx_get_cattr(psk_node, "cleartext-symmetric-key");
|
||||
if (preshared_key_data)
|
||||
fprintf(wg_fp, "PresharedKey = %s\n", preshared_key_data);
|
||||
}
|
||||
}
|
||||
|
||||
if (endpoint) {
|
||||
if (!endpoint_port)
|
||||
endpoint_port = "51820"; /* Default port */
|
||||
fprintf(wg_fp, "Endpoint = %s:%s\n", endpoint, endpoint_port);
|
||||
}
|
||||
|
||||
write_allowed_ips(wg_fp, peer_override, bag_peer);
|
||||
|
||||
if (keepalive)
|
||||
fprintf(wg_fp, "PersistentKeepalive = %s\n", keepalive);
|
||||
}
|
||||
|
||||
|
||||
int wireguard_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip, struct dagger *net)
|
||||
{
|
||||
const char *ifname, *listen_port, *private_key_ref, *private_key_data;
|
||||
struct lyd_node *wg, *key_node, *bag_peer, *pub_key_bag;
|
||||
FILE *wg_fp = NULL;
|
||||
FILE *wg_sh = NULL;
|
||||
mode_t old_umask;
|
||||
|
||||
ifname = lydx_get_cattr(cif, "name");
|
||||
wg = lydx_get_child(cif, "wireguard");
|
||||
if (!wg)
|
||||
return -EINVAL;
|
||||
|
||||
listen_port = lydx_get_cattr(wg, "listen-port");
|
||||
private_key_ref = lydx_get_cattr(wg, "private-key");
|
||||
|
||||
key_node = lydx_get_xpathf(cif, "../../keystore/asymmetric-keys/asymmetric-key[name='%s']",
|
||||
private_key_ref);
|
||||
private_key_data = lydx_get_cattr(key_node, "cleartext-private-key");
|
||||
|
||||
fprintf(ip, "link add dev %s type wireguard\n", ifname);
|
||||
|
||||
/* Set umask to create config file with limited permissions (0600) */
|
||||
old_umask = umask(0177);
|
||||
wg_fp = fopenf("w", WIREGUARD_CONFIG, ifname);
|
||||
umask(old_umask);
|
||||
if (!wg_fp)
|
||||
return -errno;
|
||||
|
||||
fprintf(wg_fp, "[Interface]\n");
|
||||
fprintf(wg_fp, "PrivateKey = %s\n", private_key_data);
|
||||
fprintf(wg_fp, "ListenPort = %s\n", listen_port);
|
||||
|
||||
LYX_LIST_FOR_EACH(lyd_child(wg), bag_peer, "peers") {
|
||||
const char *public_key_bag_ref = lydx_get_cattr(bag_peer, "public-key-bag");
|
||||
|
||||
pub_key_bag = lydx_get_xpathf(cif, "../../truststore/public-key-bags/public-key-bag[name='%s']",
|
||||
public_key_bag_ref);
|
||||
if (pub_key_bag) {
|
||||
struct lyd_node *pub_key, *peer_override;
|
||||
const char *public_key_name, *public_key_data;
|
||||
|
||||
LYX_LIST_FOR_EACH(lyd_child(pub_key_bag), pub_key, "public-key") {
|
||||
public_key_name = lydx_get_cattr(pub_key, "name");
|
||||
public_key_data = lydx_get_cattr(pub_key, "public-key");
|
||||
|
||||
if (!public_key_data)
|
||||
continue;
|
||||
|
||||
/* Check if there's a peer-specific override for this key */
|
||||
peer_override = lydx_get_xpathf(bag_peer, "peer[public-key='%s']", public_key_name);
|
||||
|
||||
write_peer(wg_fp, cif, bag_peer, peer_override, public_key_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(wg_fp);
|
||||
|
||||
/* Create activation script */
|
||||
wg_sh = dagger_fopen_net_init(net, ifname, NETDAG_INIT_POST, "enable-wireguard.sh");
|
||||
|
||||
fprintf(wg_sh, "wg setconf %s ", ifname);
|
||||
fprintf(wg_sh, WIREGUARD_CONFIG, ifname);
|
||||
fprintf(wg_sh, "\n");
|
||||
|
||||
fclose(wg_sh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -108,6 +108,8 @@ static int ifchange_cand_infer_type(sr_session_ctx_t *session, const char *path)
|
||||
inferred.data.string_val = "infix-if-type:gretap";
|
||||
else if (!fnmatch("vxlan+([0-9])", ifname, FNM_EXTMATCH))
|
||||
inferred.data.string_val = "infix-if-type:vxlan";
|
||||
else if (!fnmatch("wg+([0-9])", ifname, FNM_EXTMATCH))
|
||||
inferred.data.string_val = "infix-if-type:wireguard";
|
||||
|
||||
free(ifname);
|
||||
|
||||
@@ -419,6 +421,8 @@ static int netdag_gen_afspec_add(sr_session_ctx_t *session, struct dagger *net,
|
||||
return vxlan_gen(NULL, cif, ip);
|
||||
case IFT_WIFI:
|
||||
return wifi_add_iface(cif, net);
|
||||
case IFT_WIREGUARD:
|
||||
return wireguard_gen(NULL, cif, ip, net);
|
||||
case IFT_ETH:
|
||||
return netdag_gen_ethtool(net, cif, dif);
|
||||
case IFT_LO:
|
||||
@@ -457,6 +461,7 @@ static int netdag_gen_afspec_set(sr_session_ctx_t *session, struct dagger *net,
|
||||
case IFT_GRETAP:
|
||||
case IFT_VETH:
|
||||
case IFT_VXLAN:
|
||||
case IFT_WIREGUARD:
|
||||
case IFT_LO:
|
||||
return 0;
|
||||
|
||||
@@ -494,6 +499,8 @@ static bool netdag_must_del(struct lyd_node *dif, struct lyd_node *cif)
|
||||
return lydx_get_descendant(lyd_child(dif), "veth", NULL);
|
||||
case IFT_VXLAN:
|
||||
return lydx_get_descendant(lyd_child(dif), "vxlan", NULL);
|
||||
case IFT_WIREGUARD:
|
||||
return lydx_get_descendant(lyd_child(dif), "wireguard", NULL);
|
||||
case IFT_UNKNOWN:
|
||||
ERR_IFACE(cif, -EINVAL, "unsupported interface type \"%s\"",
|
||||
lydx_get_cattr(cif, "type"));
|
||||
@@ -579,6 +586,7 @@ static int netdag_gen_iface_del(struct dagger *net, struct lyd_node *dif,
|
||||
case IFT_LAG:
|
||||
case IFT_VLAN:
|
||||
case IFT_VXLAN:
|
||||
case IFT_WIREGUARD:
|
||||
case IFT_UNKNOWN:
|
||||
link_gen_del(dif, ip);
|
||||
break;
|
||||
@@ -744,6 +752,7 @@ static int netdag_init_iface(struct lyd_node *cif)
|
||||
case IFT_GRETAP:
|
||||
case IFT_LO:
|
||||
case IFT_VXLAN:
|
||||
case IFT_WIREGUARD:
|
||||
case IFT_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
_map(IFT_VLAN, "infix-if-type:vlan") \
|
||||
_map(IFT_VXLAN, "infix-if-type:vxlan") \
|
||||
_map(IFT_WIFI, "infix-if-type:wifi") \
|
||||
_map(IFT_WIREGUARD,"infix-if-type:wireguard") \
|
||||
/* */
|
||||
|
||||
enum iftype {
|
||||
@@ -152,4 +153,7 @@ int ifchange_cand_infer_dhcp(sr_session_ctx_t *session, const char *path);
|
||||
/* if-vxlan.c */
|
||||
int vxlan_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip);
|
||||
|
||||
/* infix-if-wireguard */
|
||||
int wireguard_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip, struct dagger *net);
|
||||
|
||||
#endif /* CONFD_INTERFACES_H_ */
|
||||
|
||||
@@ -30,7 +30,7 @@ MODULES=(
|
||||
"infix-hardware@2025-12-04.yang"
|
||||
"ieee802-dot1q-types@2022-10-29.yang"
|
||||
"infix-ip@2025-11-02.yang"
|
||||
"infix-if-type@2025-02-12.yang"
|
||||
"infix-if-type@2026-01-07.yang"
|
||||
"infix-routing@2025-12-02.yang"
|
||||
"ieee802-dot1ab-lldp@2022-03-15.yang"
|
||||
"infix-lldp@2025-05-05.yang"
|
||||
@@ -49,8 +49,8 @@ MODULES=(
|
||||
"infix-factory-default@2023-06-28.yang"
|
||||
"infix-interfaces@2025-11-06.yang -e vlan-filtering"
|
||||
"ietf-crypto-types -e cleartext-symmetric-keys"
|
||||
"infix-crypto-types@2025-06-17.yang"
|
||||
"infix-crypto-types@2025-11-09.yang"
|
||||
"ietf-keystore -e symmetric-keys"
|
||||
"infix-keystore@2025-12-10.yang"
|
||||
"infix-ntp@2025-12-03.yang"
|
||||
"infix-keystore@2025-12-17.yang"
|
||||
)
|
||||
|
||||
@@ -6,6 +6,9 @@ module infix-crypto-types {
|
||||
prefix ct;
|
||||
}
|
||||
|
||||
revision 2025-11-09 {
|
||||
description "Add Wireguard public/private key and sha";
|
||||
}
|
||||
revision 2025-06-17 {
|
||||
description "Add Wi-Fi secret support.";
|
||||
}
|
||||
@@ -28,6 +31,7 @@ module infix-crypto-types {
|
||||
base public-key-format;
|
||||
base ct:ssh-public-key-format;
|
||||
}
|
||||
|
||||
identity symmetric-key-format {
|
||||
description
|
||||
"Base for symmetric key format";
|
||||
@@ -38,4 +42,29 @@ module infix-crypto-types {
|
||||
description
|
||||
"WiFi secret key";
|
||||
}
|
||||
|
||||
identity x25519-public-key-format {
|
||||
base public-key-format;
|
||||
base ct:public-key-format;
|
||||
description
|
||||
"X25519 (Curve25519) public key format for Diffie-Hellman key exchange.
|
||||
This is the format used by WireGuard.";
|
||||
}
|
||||
|
||||
identity x25519-private-key-format {
|
||||
base private-key-format;
|
||||
base ct:private-key-format;
|
||||
description
|
||||
"X25519 (Curve25519) private key format for Diffie-Hellman key exchange.
|
||||
This is the format used by WireGuard.";
|
||||
}
|
||||
|
||||
identity wireguard-symmetric-key-format {
|
||||
base ct:symmetric-key-format;
|
||||
base symmetric-key-format;
|
||||
description
|
||||
"WireGuard pre-shared key format.
|
||||
32-byte base64-encoded key used as an optional additional layer
|
||||
of symmetric encryption for post-quantum resistance.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,11 @@ module infix-if-type {
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Infix extensions to IANA interfaces types";
|
||||
|
||||
revision 2026-01-07 {
|
||||
description "Add interface type wifi and wireguard";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
revision 2025-02-12 {
|
||||
description "Remove interface type etherlike.";
|
||||
reference "internal";
|
||||
@@ -81,6 +86,9 @@ module infix-if-type {
|
||||
identity vxlan {
|
||||
base infix-interface-type;
|
||||
}
|
||||
identity wireguard {
|
||||
base infix-interface-type;
|
||||
}
|
||||
identity lag {
|
||||
base infix-interface-type;
|
||||
base ianaift:ieee8023adLag;
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
submodule infix-if-wireguard {
|
||||
yang-version 1.1;
|
||||
belongs-to infix-interfaces {
|
||||
prefix infix-if;
|
||||
}
|
||||
|
||||
import ietf-interfaces {
|
||||
prefix if;
|
||||
}
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import infix-crypto-types {
|
||||
prefix ixct;
|
||||
}
|
||||
import ietf-keystore {
|
||||
prefix ks;
|
||||
}
|
||||
import infix-keystore {
|
||||
prefix infix-ks;
|
||||
}
|
||||
import ietf-truststore {
|
||||
prefix ts;
|
||||
}
|
||||
import infix-if-type {
|
||||
prefix infixift;
|
||||
}
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "WireGuard VPN tunnel interface";
|
||||
|
||||
revision 2025-11-09 {
|
||||
description "Initial revision";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
typedef port {
|
||||
type inet:port-number;
|
||||
description
|
||||
"WireGuard UDP port. Valid range: 0..65535.";
|
||||
}
|
||||
|
||||
typedef keepalive-interval {
|
||||
type uint16 {
|
||||
range "1..65535";
|
||||
}
|
||||
units "seconds";
|
||||
description
|
||||
"Persistent keepalive interval in seconds.
|
||||
|
||||
A keepalive packet will be sent to the peer endpoint at this
|
||||
interval if no traffic has been exchanged. This is useful for
|
||||
traversing NAT and firewalls that may close the UDP connection
|
||||
after a period of inactivity.
|
||||
|
||||
Recommended value is 25 seconds for peers behind NAT.";
|
||||
}
|
||||
|
||||
grouping peer-settings {
|
||||
description
|
||||
"Common WireGuard peer configuration settings.
|
||||
|
||||
These settings can be applied at the key-bag level (affecting all
|
||||
keys in the bag) or at individual peer level (overriding key-bag
|
||||
settings for specific keys).";
|
||||
|
||||
leaf preshared-key {
|
||||
type ks:central-symmetric-key-ref;
|
||||
description
|
||||
"Optional preshared key for additional layer of symmetric encryption.
|
||||
|
||||
This provides post-quantum resistance as an attacker would need
|
||||
to break both the Curve25519 key exchange and this symmetric key.";
|
||||
must "derived-from-or-self(deref(.)/../ks:key-format, 'ixct:wireguard-symmetric-key-format')" {
|
||||
error-message "Preshared key must be in wireguard-symmetric-key-format";
|
||||
}
|
||||
}
|
||||
|
||||
leaf endpoint {
|
||||
type inet:host;
|
||||
description
|
||||
"Peer endpoint address (IP address or DNS hostname).
|
||||
|
||||
If not specified, this peer can only be a responder and cannot
|
||||
initiate connections. WireGuard will learn the endpoint from
|
||||
incoming authenticated packets.";
|
||||
}
|
||||
|
||||
leaf endpoint-port {
|
||||
type port;
|
||||
description "Peer endpoint UDP port";
|
||||
}
|
||||
|
||||
leaf-list allowed-ips {
|
||||
type inet:ip-prefix;
|
||||
description
|
||||
"List of IP address ranges (in CIDR notation) that are allowed
|
||||
to be used as source addresses inside the tunnel from this peer.
|
||||
|
||||
This also controls which destination addresses will be routed
|
||||
to this peer. For example:
|
||||
- '10.0.0.2/32' allows only this single IP
|
||||
- '10.0.0.0/24' allows the entire subnet
|
||||
- '0.0.0.0/0, ::/0' routes all traffic through this peer
|
||||
|
||||
WireGuard uses this as a cryptographic routing table.
|
||||
|
||||
IMPORTANT: Allowed-IPs must be unique across all peers. If
|
||||
multiple peers have overlapping allowed-ips, only the last
|
||||
peer will be used for routing. When configuring at the
|
||||
key-bag level, only use allowed-ips if all peers genuinely
|
||||
need identical routing (rare). For typical hub-and-spoke
|
||||
scenarios, use per-peer configuration with unique allowed-ips
|
||||
for each client (e.g., 10.0.0.2/32, 10.0.0.3/32, etc.).";
|
||||
}
|
||||
|
||||
leaf persistent-keepalive {
|
||||
type keepalive-interval;
|
||||
description
|
||||
"Interval in seconds to send keepalive packets to this peer.
|
||||
|
||||
If not specified (or set to 0), keepalive is disabled.
|
||||
Use this when the peer is behind NAT or a firewall that may
|
||||
close the UDP connection after inactivity.";
|
||||
}
|
||||
}
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
when "derived-from-or-self(if:type, 'infixift:wireguard')" {
|
||||
description "Only shown for if:type infixift:wireguard";
|
||||
}
|
||||
container wireguard {
|
||||
description "WireGuard VPN configuration";
|
||||
|
||||
leaf listen-port {
|
||||
type port;
|
||||
default 51820;
|
||||
description "Local UDP port to listen on for incoming WireGuard traffic";
|
||||
}
|
||||
|
||||
leaf private-key {
|
||||
type ks:central-asymmetric-key-ref;
|
||||
mandatory true;
|
||||
description "Reference to WireGuard private key (X25519/Curve25519 format)";
|
||||
must "not(deref(.)/ks:public-key-format) or "
|
||||
+ "(derived-from-or-self(deref(.)/ks:public-key-format, 'ixct:x25519-public-key-format') and "
|
||||
+ "derived-from-or-self(deref(.)/ks:private-key-format, 'ixct:x25519-private-key-format'))" {
|
||||
error-message "Private key must be in WireGuard (X25519/Curve25519) format";
|
||||
}
|
||||
}
|
||||
|
||||
list peers {
|
||||
key "public-key-bag";
|
||||
description
|
||||
"Peers from a public key bag with common settings.
|
||||
|
||||
If the bag contains a single key, bag-level settings (endpoint,
|
||||
allowed-ips, etc.) apply to that peer. If the bag contains multiple
|
||||
keys, individual peer configuration is required for each key - you
|
||||
must provide a 'peer' entry for each public key in the bag with
|
||||
unique settings like endpoint and allowed-ips.";
|
||||
|
||||
must "count(../../../../ts:truststore/ts:public-key-bags/ts:public-key-bag[ts:name=current()/public-key-bag]/ts:public-key) = 1 or "
|
||||
+ "count(./peer) = count(../../../../ts:truststore/ts:public-key-bags/ts:public-key-bag[ts:name=current()/public-key-bag]/ts:public-key)" {
|
||||
error-message "When a key-bag contains multiple keys, individual peer "
|
||||
+ "configuration is required for each key. Either use a "
|
||||
+ "key-bag with a single key for shared settings, or provide "
|
||||
+ "a 'peer' entry for each key in the bag with unique settings.";
|
||||
}
|
||||
|
||||
leaf public-key-bag {
|
||||
type ts:central-public-key-bag-ref;
|
||||
must "not(deref(.)/ts:public-key-format) or "
|
||||
+ "(derived-from-or-self(deref(.)/ts:public-key-format, 'ixct:x25519-public-key-format'))" {
|
||||
error-message "Public key must be in WireGuard (X25519/Curve25519) format";
|
||||
}
|
||||
description "Reference to public key bag containing peer public keys";
|
||||
}
|
||||
|
||||
uses peer-settings {
|
||||
refine endpoint-port {
|
||||
default 51820;
|
||||
}
|
||||
}
|
||||
|
||||
list peer {
|
||||
key "public-key";
|
||||
description
|
||||
"Individual peer with override settings.
|
||||
|
||||
Settings specified here override the key-bag level settings
|
||||
for this specific peer.";
|
||||
|
||||
leaf public-key {
|
||||
type leafref {
|
||||
path "../../../../../../ts:truststore/ts:public-key-bags/" +
|
||||
"ts:public-key-bag[ts:name=current()/../../public-key-bag]/" +
|
||||
"ts:public-key/ts:name";
|
||||
}
|
||||
description "Name of the peer's public key within the referenced key-bag";
|
||||
}
|
||||
|
||||
uses peer-settings;
|
||||
}
|
||||
}
|
||||
|
||||
container peer-status {
|
||||
config false;
|
||||
description "Operational state for WireGuard peers";
|
||||
|
||||
list peer {
|
||||
key "public-key";
|
||||
description "Per-peer operational statistics and status";
|
||||
|
||||
leaf public-key {
|
||||
type string {
|
||||
pattern '[A-Za-z0-9+/]{43}=';
|
||||
}
|
||||
description
|
||||
"WireGuard public key of the peer in base64 encoding.
|
||||
|
||||
This is the actual key value, not a keystore reference.";
|
||||
}
|
||||
|
||||
leaf latest-handshake {
|
||||
type yang:date-and-time;
|
||||
description
|
||||
"Timestamp of the most recent successful handshake with this peer.
|
||||
|
||||
If no handshake has occurred yet, this leaf will not be present.
|
||||
A successful handshake indicates that the peer is authenticated
|
||||
and a secure session has been established.";
|
||||
}
|
||||
|
||||
leaf endpoint-address {
|
||||
type inet:ip-address;
|
||||
description
|
||||
"The actual IP address from which packets were last received
|
||||
from this peer.
|
||||
|
||||
This may differ from the configured endpoint if:
|
||||
- The peer is roaming (changed IP address)
|
||||
- The configured endpoint is a DNS hostname
|
||||
- No endpoint was configured (learned from incoming packets)
|
||||
|
||||
If no packets have been received, this leaf will not be present.";
|
||||
}
|
||||
|
||||
leaf endpoint-port {
|
||||
type port;
|
||||
description
|
||||
"The actual UDP port from which packets were last received
|
||||
from this peer.
|
||||
|
||||
If no packets have been received, this leaf will not be present.";
|
||||
}
|
||||
|
||||
container transfer {
|
||||
description "Data transfer statistics for this peer";
|
||||
|
||||
leaf tx-bytes {
|
||||
type yang:counter64;
|
||||
units "bytes";
|
||||
description
|
||||
"Total number of bytes transmitted (sent) to this peer.
|
||||
|
||||
This counts encrypted payload bytes sent through the tunnel.";
|
||||
}
|
||||
|
||||
leaf rx-bytes {
|
||||
type yang:counter64;
|
||||
units "bytes";
|
||||
description
|
||||
"Total number of bytes received from this peer.
|
||||
|
||||
This counts decrypted payload bytes received through the tunnel.";
|
||||
}
|
||||
}
|
||||
|
||||
leaf connection-status {
|
||||
type enumeration {
|
||||
enum down {
|
||||
description
|
||||
"No handshake has occurred, or the last handshake is too old.
|
||||
|
||||
The peer is not considered connected.";
|
||||
}
|
||||
enum up {
|
||||
description
|
||||
"A recent handshake has occurred and the connection is active.
|
||||
|
||||
Typically means a handshake within the last 2-3 minutes.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Current connection status with this peer.
|
||||
|
||||
This is derived from the latest-handshake timestamp and indicates
|
||||
whether the tunnel is currently operational.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
infix-if-wireguard.yang
|
||||
@@ -34,6 +34,7 @@ module infix-interfaces {
|
||||
include infix-if-gre;
|
||||
include infix-if-vxlan;
|
||||
include infix-if-wifi;
|
||||
include infix-if-wireguard;
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
|
||||
@@ -12,6 +12,9 @@ module infix-keystore {
|
||||
prefix infix-ct;
|
||||
}
|
||||
|
||||
revision 2025-12-17 {
|
||||
description "Add WireGuard support";
|
||||
}
|
||||
revision 2025-12-10 {
|
||||
description "Adapt to changes in final version of ietf-keystore";
|
||||
}
|
||||
@@ -36,18 +39,10 @@ module infix-keystore {
|
||||
}
|
||||
}
|
||||
deviation "/ks:keystore/ks:symmetric-keys/ks:symmetric-key/ks:key-format" {
|
||||
deviate not-supported;
|
||||
}
|
||||
augment "/ks:keystore/ks:symmetric-keys/ks:symmetric-key" {
|
||||
leaf key-format {
|
||||
deviate replace {
|
||||
type identityref {
|
||||
base infix-ct:symmetric-key-format;
|
||||
}
|
||||
description
|
||||
"Identifies the symmetric key's format
|
||||
|
||||
Valid symmetric key formats are:
|
||||
wifi-preshared-key-format - WiFi preshared key";
|
||||
}
|
||||
}
|
||||
deviation "/ks:keystore/ks:symmetric-keys/ks:symmetric-key/ks:key-type/ks:cleartext-symmetric-key" {
|
||||
@@ -61,7 +56,16 @@ module infix-keystore {
|
||||
"(string-length(.) >= 8 and string-length(.) <= 63)" {
|
||||
error-message "WiFi pre-shared key must be 8-63 characters long";
|
||||
}
|
||||
description "WiFi pre-shared key: 8-63 printable ASCII characters";
|
||||
must "../infix-ks:key-format != 'infix-ct:wireguard-symmetric-key-format' or " +
|
||||
"string-length(.) = 44" {
|
||||
error-message "WireGuard pre-shared key must be 44 characters (32-byte base64-encoded)";
|
||||
}
|
||||
description
|
||||
"Cleartext symmetric key value.
|
||||
|
||||
Format depends on key-format:
|
||||
- WiFi pre-shared key: 8-63 printable ASCII characters
|
||||
- WireGuard pre-shared key: 32-byte base64-encoded key (44 chars with padding)";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1114,6 +1114,7 @@ class Iface:
|
||||
self.gre = self.data.get('infix-interfaces:gre')
|
||||
self.vxlan = self.data.get('infix-interfaces:vxlan')
|
||||
self.wifi = self.data.get('infix-interfaces:wifi')
|
||||
self.wireguard = self.data.get('infix-interfaces:wireguard')
|
||||
|
||||
if self.data.get('infix-interfaces:vlan'):
|
||||
self.lower_if = self.data.get('infix-interfaces:vlan', None).get('lower-layer-if',None)
|
||||
@@ -1148,6 +1149,9 @@ class Iface:
|
||||
def is_gretap(self):
|
||||
return self.data['type'] == "infix-if-type:gretap"
|
||||
|
||||
def is_wireguard(self):
|
||||
return self.data['type'] == "infix-if-type:wireguard"
|
||||
|
||||
def oper(self, detail=False):
|
||||
"""Remap in brief overview to fit column widths."""
|
||||
if not detail and self.oper_status == "lower-layer-down":
|
||||
@@ -1219,6 +1223,23 @@ class Iface:
|
||||
row = self._pr_proto_common("vxlan", True, pipe);
|
||||
print(row)
|
||||
|
||||
def pr_proto_wireguard(self, pipe=''):
|
||||
row = self._pr_proto_common("wireguard", False, pipe)
|
||||
|
||||
if self.wireguard:
|
||||
peer_status = self.wireguard.get('peer-status', {})
|
||||
peers = peer_status.get('peer', [])
|
||||
total_peers = len(peers)
|
||||
up_peers = sum(1 for p in peers if p.get('connection-status') == 'up')
|
||||
|
||||
if total_peers > 0:
|
||||
row += f"{total_peers} peer"
|
||||
if total_peers != 1:
|
||||
row += "s"
|
||||
row += f" ({up_peers} up)"
|
||||
|
||||
print(row)
|
||||
|
||||
def pr_proto_loopack(self, pipe=''):
|
||||
row = self._pr_proto_common("loopback", False, pipe);
|
||||
print(row)
|
||||
@@ -1471,6 +1492,12 @@ class Iface:
|
||||
self.pr_proto_ipv4()
|
||||
self.pr_proto_ipv6()
|
||||
|
||||
def pr_wireguard(self):
|
||||
self.pr_name(pipe="")
|
||||
self.pr_proto_wireguard()
|
||||
self.pr_proto_ipv4()
|
||||
self.pr_proto_ipv6()
|
||||
|
||||
def pr_wifi(self):
|
||||
self.pr_name(pipe="")
|
||||
self.pr_proto_wifi()
|
||||
@@ -1598,9 +1625,6 @@ class Iface:
|
||||
print(f"{'in-octets':<{20}}: {self.in_octets}")
|
||||
print(f"{'out-octets':<{20}}: {self.out_octets}")
|
||||
|
||||
frame = get_json_data([], self.data,'ieee802-ethernet-interface:ethernet',
|
||||
'statistics', 'frame')
|
||||
|
||||
if self.wifi:
|
||||
# Detect mode: AP has "stations", Station has "rssi" or "scan-results"
|
||||
ap = self.wifi.get('access-point')
|
||||
@@ -1635,6 +1659,46 @@ class Iface:
|
||||
print(f"{'remote address':<{20}}: {self.vxlan['remote']}")
|
||||
print(f"{'VxLAN id':<{20}}: {self.vxlan['vni']}")
|
||||
|
||||
if self.wireguard:
|
||||
peer_status = self.wireguard.get('peer-status', {})
|
||||
peers = peer_status.get('peer', [])
|
||||
if peers:
|
||||
print(f"{'peers':<{20}}: {len(peers)}")
|
||||
for idx, peer in enumerate(peers, 1):
|
||||
print(f"\n Peer {idx}:")
|
||||
|
||||
# Public key (always 44 chars: 43 + '=')
|
||||
if pubkey := peer.get('public-key'):
|
||||
print(f" {'public key':<{18}}: {pubkey}")
|
||||
|
||||
# Connection status with color
|
||||
status = peer.get('connection-status', 'unknown')
|
||||
if status == 'up':
|
||||
status_str = Decore.green(status.upper())
|
||||
else:
|
||||
status_str = Decore.red(status.upper())
|
||||
print(f" {'status':<{18}}: {status_str}")
|
||||
|
||||
# Endpoint information
|
||||
if endpoint := peer.get('endpoint-address'):
|
||||
port = peer.get('endpoint-port', '')
|
||||
endpoint_str = f"{endpoint}:{port}" if port else endpoint
|
||||
print(f" {'endpoint':<{18}}: {endpoint_str}")
|
||||
|
||||
# Latest handshake
|
||||
if handshake := peer.get('latest-handshake'):
|
||||
print(f" {'latest handshake':<{18}}: {handshake}")
|
||||
|
||||
# Transfer statistics
|
||||
if transfer := peer.get('transfer'):
|
||||
tx = transfer.get('tx-bytes', '0')
|
||||
rx = transfer.get('rx-bytes', '0')
|
||||
print(f" {'transfer tx':<{18}}: {tx} bytes")
|
||||
print(f" {'transfer rx':<{18}}: {rx} bytes")
|
||||
|
||||
|
||||
frame = get_json_data([], self.data,'ieee802-ethernet-interface:ethernet',
|
||||
'statistics', 'frame')
|
||||
if frame:
|
||||
print("")
|
||||
for key, val in frame.items():
|
||||
@@ -1799,6 +1863,10 @@ def pr_interface_list(json):
|
||||
iface.pr_vxlan()
|
||||
continue
|
||||
|
||||
if iface.is_wireguard():
|
||||
iface.pr_wireguard()
|
||||
continue
|
||||
|
||||
if iface.is_wifi():
|
||||
iface.pr_wifi()
|
||||
continue
|
||||
|
||||
@@ -9,6 +9,7 @@ from . import tun
|
||||
from . import veth
|
||||
from . import vlan
|
||||
from . import wifi
|
||||
from . import wireguard
|
||||
|
||||
|
||||
def statistics(iplink):
|
||||
@@ -27,6 +28,7 @@ def statistics(iplink):
|
||||
|
||||
def iplink2yang_type(iplink):
|
||||
ifname=iplink["ifname"]
|
||||
|
||||
match iplink["link_type"]:
|
||||
case "loopback":
|
||||
return "infix-if-type:loopback"
|
||||
@@ -36,6 +38,8 @@ def iplink2yang_type(iplink):
|
||||
data = HOST.run(tuple(f"ls /sys/class/net/{ifname}/wireless/".split()), default="no")
|
||||
if data != "no":
|
||||
return "infix-if-type:wifi"
|
||||
case "none":
|
||||
pass # WireGuard interfaces is for some reason link_type none
|
||||
case _:
|
||||
return "infix-if-type:other"
|
||||
|
||||
@@ -54,6 +58,8 @@ def iplink2yang_type(iplink):
|
||||
return "infix-if-type:veth"
|
||||
case "vlan":
|
||||
return "infix-if-type:vlan"
|
||||
case "wireguard":
|
||||
return "infix-if-type:wireguard"
|
||||
|
||||
return "infix-if-type:ethernet"
|
||||
|
||||
@@ -141,6 +147,9 @@ def interface(iplink, ipaddr):
|
||||
case "infix-if-type:wifi":
|
||||
if w := wifi.wifi(iplink["ifname"]):
|
||||
interface["infix-interfaces:wifi"] = w
|
||||
case "infix-if-type:wireguard":
|
||||
if wg := wireguard.wireguard(iplink):
|
||||
interface["infix-interfaces:wireguard"] = wg
|
||||
|
||||
match iplink2yang_lower(iplink):
|
||||
case "infix-interfaces:bridge-port":
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import subprocess
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from ..host import HOST
|
||||
|
||||
|
||||
def _parse_wg_show(ifname):
|
||||
"""Parse `wg show <ifname> dump` output into structured data"""
|
||||
try:
|
||||
result = HOST.run(("wg", "show", ifname, "dump"), default="")
|
||||
if not result:
|
||||
return None
|
||||
|
||||
lines = result.strip().split('\n')
|
||||
if len(lines) < 2: # Need at least interface line + one peer
|
||||
return None
|
||||
|
||||
peers = []
|
||||
# Skip first line (interface info), process peer lines
|
||||
for line in lines[1:]:
|
||||
parts = line.split('\t')
|
||||
if len(parts) < 8:
|
||||
continue
|
||||
|
||||
public_key, preshared_key, endpoint, allowed_ips, \
|
||||
latest_handshake, rx_bytes, tx_bytes, persistent_keepalive = parts
|
||||
|
||||
peer = {
|
||||
"public_key": public_key,
|
||||
"endpoint": endpoint if endpoint != "(none)" else None,
|
||||
"allowed_ips": allowed_ips.split(',') if allowed_ips else [],
|
||||
"latest_handshake": int(latest_handshake) if latest_handshake != "0" else None,
|
||||
"rx_bytes": int(rx_bytes),
|
||||
"tx_bytes": int(tx_bytes),
|
||||
}
|
||||
peers.append(peer)
|
||||
|
||||
return peers
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _format_timestamp(epoch_seconds):
|
||||
"""Convert Unix timestamp to YANG date-and-time format"""
|
||||
if not epoch_seconds:
|
||||
return None
|
||||
dt = datetime.fromtimestamp(epoch_seconds, tz=timezone.utc)
|
||||
# YANG date-and-time requires timezone with colon: +00:00 not +0000
|
||||
timestamp = dt.strftime("%Y-%m-%dT%H:%M:%S%z")
|
||||
# Insert colon in timezone offset: +0000 -> +00:00
|
||||
return timestamp[:-2] + ':' + timestamp[-2:]
|
||||
|
||||
|
||||
def _parse_endpoint(endpoint_str):
|
||||
"""Parse endpoint string like '192.168.1.1:51820' or '[2001:db8::1]:51820'"""
|
||||
if not endpoint_str or endpoint_str == "(none)":
|
||||
return None, None
|
||||
|
||||
# Handle IPv6 with brackets
|
||||
if endpoint_str.startswith('['):
|
||||
addr_end = endpoint_str.find(']')
|
||||
if addr_end == -1:
|
||||
return None, None
|
||||
addr = endpoint_str[1:addr_end]
|
||||
port_part = endpoint_str[addr_end+1:]
|
||||
port = int(port_part.lstrip(':')) if ':' in port_part else None
|
||||
return addr, port
|
||||
|
||||
# Handle IPv4
|
||||
parts = endpoint_str.rsplit(':', 1)
|
||||
if len(parts) == 2:
|
||||
return parts[0], int(parts[1])
|
||||
return parts[0], None
|
||||
|
||||
|
||||
def _connection_status(latest_handshake_epoch):
|
||||
"""Determine connection status based on handshake time"""
|
||||
if not latest_handshake_epoch:
|
||||
return "down"
|
||||
|
||||
# Consider connection up if handshake within last 3 minutes
|
||||
age = datetime.now(timezone.utc).timestamp() - latest_handshake_epoch
|
||||
return "up" if age < 180 else "down"
|
||||
|
||||
|
||||
def wireguard(iplink):
|
||||
"""Get WireGuard operational state data"""
|
||||
ifname = iplink.get("ifname")
|
||||
if not ifname:
|
||||
return None
|
||||
|
||||
peers_data = _parse_wg_show(ifname)
|
||||
if not peers_data:
|
||||
return None
|
||||
|
||||
peers = []
|
||||
for peer_data in peers_data:
|
||||
peer = {
|
||||
"public-key": peer_data["public_key"]
|
||||
}
|
||||
|
||||
# Connection status (always include)
|
||||
if peer_data["latest_handshake"]:
|
||||
peer["latest-handshake"] = _format_timestamp(peer_data["latest_handshake"])
|
||||
peer["connection-status"] = _connection_status(peer_data["latest_handshake"])
|
||||
else:
|
||||
peer["connection-status"] = "down"
|
||||
|
||||
# Parse endpoint
|
||||
if peer_data["endpoint"]:
|
||||
addr, port = _parse_endpoint(peer_data["endpoint"])
|
||||
if addr:
|
||||
peer["endpoint-address"] = addr
|
||||
if port:
|
||||
peer["endpoint-port"] = port
|
||||
|
||||
# Transfer statistics
|
||||
if peer_data["tx_bytes"] or peer_data["rx_bytes"]:
|
||||
peer["transfer"] = {
|
||||
"tx-bytes": str(peer_data["tx_bytes"]),
|
||||
"rx-bytes": str(peer_data["rx_bytes"]),
|
||||
}
|
||||
|
||||
peers.append(peer)
|
||||
|
||||
return {"peer-status": {"peer": peers}} if peers else None
|
||||
@@ -7,3 +7,12 @@
|
||||
|
||||
- name: Tunnel TTL verification
|
||||
suite: tunnel_ttl/test.yaml
|
||||
|
||||
- name: WireGuard Point-to-Point
|
||||
case: wireguard_p2p/test.py
|
||||
|
||||
- name: WireGuard multipoint
|
||||
case: wireguard_multipoint/test.py
|
||||
|
||||
- name: WireGuard Roadwarrior
|
||||
case: wireguard_roadwarrior/test.py
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
test.adoc
|
||||
@@ -0,0 +1,57 @@
|
||||
=== WireGuard multipoint
|
||||
|
||||
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/interfaces/wireguard_multipoint]
|
||||
|
||||
==== Description
|
||||
|
||||
Set up a WireGuard hub-and-spoke topology with one server (hub) and two
|
||||
clients (spokes). The server acts as a central point through which clients
|
||||
can communicate. Host namespaces are connected behind the server and client1
|
||||
to test routing through the WireGuard mesh.
|
||||
|
||||
This test verifies:
|
||||
|
||||
- WireGuard hub-and-spoke topology with multiple peers
|
||||
- Mixed IPv4/IPv6 tunnel endpoints (client1 uses IPv4, client2 uses IPv6)
|
||||
- Dual-stack WireGuard tunnels carrying both IPv4 and IPv6 traffic
|
||||
- Advanced key management with preshared keys for post-quantum resistance
|
||||
- Persistent keepalive configuration for NAT traversal
|
||||
- Different listen ports on server and clients
|
||||
- Multiple allowed-ips per peer for routing multiple subnets
|
||||
- Static routes for subnet reachability through WireGuard
|
||||
- Security boundaries enforced by allowed-ips (client2 isolated from server subnet)
|
||||
- IPv4 and IPv6 connectivity through the encrypted tunnel mesh
|
||||
- Proper routing between all nodes in the WireGuard network
|
||||
|
||||
WireGuard hub-and-spoke:
|
||||
....
|
||||
server:wg0 (10.0.0.1, fd00:0::1)
|
||||
|
|
||||
+----------------+----------------+
|
||||
| |
|
||||
client1:wg0 client2:wg0
|
||||
(10.0.0.2, fd00:0::2) (10.0.0.3, fd00:0::3)
|
||||
via IPv4 endpoint via IPv6 endpoint
|
||||
192.168.10.x 2001:db8:3c4d:20::x
|
||||
....
|
||||
|
||||
Security boundaries:
|
||||
- host:data1 can reach all WireGuard IPs (10.0.0.1, .2, .3 and fd00:0::1, ::2, ::3)
|
||||
- host:data2 can reach server and client1 WireGuard IPs, but NOT client2 (blocked by allowed-ips)
|
||||
|
||||
==== Topology
|
||||
|
||||
image::topology.svg[WireGuard multipoint topology, align=center, scaledwidth=75%]
|
||||
|
||||
==== Sequence
|
||||
|
||||
. Set up topology and attach to target DUTs
|
||||
. Configure server, client1 and client2
|
||||
. Verify IPv4 connectivity with ping 10.0.0.1, 10.0.0.2 and 10.0.0.3 from host:data1
|
||||
. Verify IPv4 connectivity with ping 10.0.0.1 and 10.0.0.2 from host:data2
|
||||
. Verify host:data2 can not ping 10.0.0.3
|
||||
. Verify IPv6 connectivity with ping fd00:0::1, fd00:0::2 and fd00:0::3 from host:data1
|
||||
. Verify IPv6 connectivity with ping fd00:0:1 and fd00:0:2 from host:data2
|
||||
. Verify host:data2 can not ping fd00:0::3
|
||||
|
||||
|
||||
@@ -0,0 +1,512 @@
|
||||
#!/usr/bin/env python3
|
||||
r"""
|
||||
Advanced WireGuard multipoint hub-and-spoke tunnel test
|
||||
|
||||
Set up a WireGuard hub-and-spoke topology with one server (hub) and two
|
||||
clients (spokes). The server acts as a central point through which clients
|
||||
can communicate. Host namespaces are connected behind the server and client1
|
||||
to test routing through the WireGuard mesh.
|
||||
|
||||
This test verifies:
|
||||
|
||||
- WireGuard hub-and-spoke topology with multiple peers
|
||||
- Mixed IPv4/IPv6 tunnel endpoints (client1 uses IPv4, client2 uses IPv6)
|
||||
- Dual-stack WireGuard tunnels carrying both IPv4 and IPv6 traffic
|
||||
- Advanced key management with preshared keys for post-quantum resistance
|
||||
- Persistent keepalive configuration for NAT traversal
|
||||
- Different listen ports on server and clients
|
||||
- Multiple allowed-ips per peer for routing multiple subnets
|
||||
- Static routes for subnet reachability through WireGuard
|
||||
- Security boundaries enforced by allowed-ips (client2 isolated from server subnet)
|
||||
- IPv4 and IPv6 connectivity through the encrypted tunnel mesh
|
||||
- Proper routing between all nodes in the WireGuard network
|
||||
|
||||
WireGuard hub-and-spoke:
|
||||
....
|
||||
server:wg0 (10.0.0.1, fd00:0::1)
|
||||
|
|
||||
+----------------+----------------+
|
||||
| |
|
||||
client1:wg0 client2:wg0
|
||||
(10.0.0.2, fd00:0::2) (10.0.0.3, fd00:0::3)
|
||||
via IPv4 endpoint via IPv6 endpoint
|
||||
192.168.10.x 2001:db8:3c4d:20::x
|
||||
....
|
||||
|
||||
Security boundaries:
|
||||
- host:data1 can reach all WireGuard IPs (10.0.0.1, .2, .3 and fd00:0::1, ::2, ::3)
|
||||
- host:data2 can reach server and client1 WireGuard IPs, but NOT client2 (blocked by allowed-ips)
|
||||
|
||||
"""
|
||||
|
||||
import infamy
|
||||
import infamy.util as util
|
||||
|
||||
# Server keys
|
||||
server_private_key = "uIUL4AnD5QaVrwHDPHJzQ7sIQ+Q3zDdflnvfd59qa28="
|
||||
server_public_key = "qGVmu5UbNtMuZs2t9wFoOoHlvgmV+A1SyQacVb/bEV0="
|
||||
|
||||
# Client1 keys
|
||||
client1_private_key = "kNmkNlSkSh9+Va2tmFv9Va8TBCZlTBF0fKAGJf8vomo="
|
||||
client1_public_key = "ROaZyvJc5DzA2XUAAeTj2YlwDsy2w0lr3t+rWj2imAk="
|
||||
|
||||
# Client2 keys
|
||||
client2_private_key = "OPT7v/l5zICEmFIrO0U+YwA+w07l8Xo2Dp38hjGOHGY="
|
||||
client2_public_key = "Om9CPLYdK3l93GauKrq5WXo/gbcD+1CeqFpobRLLkB4="
|
||||
|
||||
# Preshared keys (256-bit symmetric keys, base64-encoded)
|
||||
psk_client1 = "zYr83O4Ykj9i1gN+/aaosJxQxCzvXv1EYOj0MX9H2K4="
|
||||
psk_client2 = "A4Gf6KCp+CL+tH2TUd9cyARpBZAH8e+9QXiPJ0t+4So="
|
||||
|
||||
|
||||
def configure_server(dut):
|
||||
dut.put_config_dicts({
|
||||
"ietf-keystore": {
|
||||
"keystore": {
|
||||
"asymmetric-keys": {
|
||||
"asymmetric-key": [{
|
||||
"name": "server-wg-key",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": server_public_key,
|
||||
"private-key-format": "infix-crypto-types:x25519-private-key-format",
|
||||
"cleartext-private-key": server_private_key
|
||||
}]
|
||||
},
|
||||
"symmetric-keys": {
|
||||
"symmetric-key": [{
|
||||
"name": "psk-client1",
|
||||
"infix-keystore:symmetric-key": psk_client1,
|
||||
"key-format": "infix-crypto-types:wireguard-symmetric-key-format"
|
||||
}, {
|
||||
"name": "psk-client2",
|
||||
"infix-keystore:symmetric-key": psk_client2,
|
||||
"key-format": "infix-crypto-types:wireguard-symmetric-key-format"
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-truststore": {
|
||||
"truststore": {
|
||||
"public-key-bags": {
|
||||
"public-key-bag": [{
|
||||
"name": "wireguard-clients",
|
||||
"public-key": [{
|
||||
"name": "client1-wg-pubkey",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": client1_public_key
|
||||
}, {
|
||||
"name": "client2-wg-pubkey",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": client2_public_key
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-interfaces": {
|
||||
"interfaces": {
|
||||
"interface": [{
|
||||
"name": server["link1"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.10.1",
|
||||
"prefix-length": 24
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
"name": server["link2"],
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "2001:db8:3c4d:20::1",
|
||||
"prefix-length": 64
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
"name": server["data"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.0.2",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "2001:db8:3c4d:02::2",
|
||||
"prefix-length": 64
|
||||
}],
|
||||
"forwarding": True
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "wg0",
|
||||
"type": "infix-if-type:wireguard",
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "10.0.0.1",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "fd00:0::1",
|
||||
"prefix-length": 64
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"wireguard": {
|
||||
"listen-port": 51820,
|
||||
"private-key": "server-wg-key",
|
||||
"peers": [{
|
||||
"public-key-bag": "wireguard-clients",
|
||||
"persistent-keepalive": 3,
|
||||
"peer": [{
|
||||
"public-key": "client1-wg-pubkey",
|
||||
"preshared-key": "psk-client1",
|
||||
"endpoint": "192.168.10.2",
|
||||
"endpoint-port": 51821,
|
||||
"allowed-ips": ["10.0.0.2/32", "192.168.1.0/24", "fd00:0::2/128", "2001:db8:3c4d:01::/64"]
|
||||
}, {
|
||||
"public-key": "client2-wg-pubkey",
|
||||
"preshared-key": "psk-client2",
|
||||
"endpoint": "2001:db8:3c4d:20::2",
|
||||
"endpoint-port": 51822,
|
||||
"allowed-ips": ["10.0.0.3/32", "fd00:0::3/128"],
|
||||
"persistent-keepalive": 5
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ietf-routing": {
|
||||
"routing": {
|
||||
"control-plane-protocols": {
|
||||
"control-plane-protocol": [{
|
||||
"type": "infix-routing:static",
|
||||
"name": "default",
|
||||
"static-routes": {
|
||||
"ipv4": {
|
||||
"route": [{
|
||||
"destination-prefix": "192.168.1.0/24",
|
||||
"next-hop": {
|
||||
"next-hop-address": "10.0.0.2"
|
||||
}
|
||||
}]
|
||||
},
|
||||
"ipv6": {
|
||||
"route": [{
|
||||
"destination-prefix": "2001:db8:3c4d:01::/64",
|
||||
"next-hop": {
|
||||
"next-hop-address": "fd00:0::2"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
def configure_client1(dut):
|
||||
dut.put_config_dicts({
|
||||
"ietf-keystore": {
|
||||
"keystore": {
|
||||
"asymmetric-keys": {
|
||||
"asymmetric-key": [{
|
||||
"name": "client1-wg-key",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": client1_public_key,
|
||||
"private-key-format": "infix-crypto-types:x25519-private-key-format",
|
||||
"cleartext-private-key": client1_private_key
|
||||
}]
|
||||
},
|
||||
"symmetric-keys": {
|
||||
"symmetric-key": [{
|
||||
"name": "psk-server",
|
||||
"infix-keystore:symmetric-key": psk_client1,
|
||||
"key-format": "infix-crypto-types:wireguard-symmetric-key-format"
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-truststore": {
|
||||
"truststore": {
|
||||
"public-key-bags": {
|
||||
"public-key-bag": [{
|
||||
"name": "wireguard-server",
|
||||
"public-key": [{
|
||||
"name": "server-wg-pubkey",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": server_public_key
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-interfaces": {
|
||||
"interfaces": {
|
||||
"interface": [{
|
||||
"name": client1["link"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.10.2",
|
||||
"prefix-length": 24
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
"name": client1["data"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.1.2",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "2001:db8:3c4d:01::2",
|
||||
"prefix-length": 64
|
||||
}],
|
||||
"forwarding": True
|
||||
}
|
||||
}, {
|
||||
"name": "wg0",
|
||||
"type": "infix-if-type:wireguard",
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "10.0.0.2",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "fd00:0::2",
|
||||
"prefix-length": 64
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"wireguard": {
|
||||
"listen-port": 51821,
|
||||
"private-key": "client1-wg-key",
|
||||
"peers": [{
|
||||
"public-key-bag": "wireguard-server",
|
||||
"preshared-key": "psk-server",
|
||||
"endpoint": "192.168.10.1",
|
||||
"endpoint-port": 51820,
|
||||
"allowed-ips": ["10.0.0.1/32", "10.0.0.3/32", "192.168.0.0/24", "fd00:0::1/128", "fd00:0::3/128", "2001:db8:3c4d:02::/64"],
|
||||
"persistent-keepalive": 3
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ietf-routing": {
|
||||
"routing": {
|
||||
"control-plane-protocols": {
|
||||
"control-plane-protocol": [{
|
||||
"type": "infix-routing:static",
|
||||
"name": "default",
|
||||
"static-routes": {
|
||||
"ipv4": {
|
||||
"route": [{
|
||||
"destination-prefix": "10.0.0.0/24",
|
||||
"next-hop": {
|
||||
"next-hop-address": "10.0.0.1"
|
||||
}
|
||||
}, {
|
||||
"destination-prefix": "192.168.0.0/16",
|
||||
"next-hop": {
|
||||
"next-hop-address": "10.0.0.1"
|
||||
}
|
||||
}]
|
||||
},
|
||||
"ipv6": {
|
||||
"route": [{
|
||||
"destination-prefix": "fd00::/64",
|
||||
"next-hop": {
|
||||
"next-hop-address": "fd00::1"
|
||||
}
|
||||
}, {
|
||||
"destination-prefix": "2001:db8:3c4d:02::/64",
|
||||
"next-hop": {
|
||||
"next-hop-address": "fd00::1"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
def configure_client2(dut):
|
||||
dut.put_config_dicts({
|
||||
"ietf-keystore": {
|
||||
"keystore": {
|
||||
"asymmetric-keys": {
|
||||
"asymmetric-key": [{
|
||||
"name": "client2-wg-key",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": client2_public_key,
|
||||
"private-key-format": "infix-crypto-types:x25519-private-key-format",
|
||||
"cleartext-private-key": client2_private_key
|
||||
}]
|
||||
},
|
||||
"symmetric-keys": {
|
||||
"symmetric-key": [{
|
||||
"name": "psk-server",
|
||||
"infix-keystore:symmetric-key": psk_client2,
|
||||
"key-format": "infix-crypto-types:wireguard-symmetric-key-format"
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-truststore": {
|
||||
"truststore": {
|
||||
"public-key-bags": {
|
||||
"public-key-bag": [{
|
||||
"name": "wireguard-server",
|
||||
"public-key": [{
|
||||
"name": "server-wg-pubkey",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": server_public_key
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-interfaces": {
|
||||
"interfaces": {
|
||||
"interface": [{
|
||||
"name": client2["link"],
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "2001:db8:3c4d:20::2",
|
||||
"prefix-length": 64
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
"name": "wg0",
|
||||
"type": "infix-if-type:wireguard",
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "10.0.0.3",
|
||||
"prefix-length": 24
|
||||
}]
|
||||
},
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "fd00:0::3",
|
||||
"prefix-length": 64
|
||||
}]
|
||||
},
|
||||
|
||||
"wireguard": {
|
||||
"listen-port": 51822,
|
||||
"private-key": "client2-wg-key",
|
||||
"peers": [{
|
||||
"public-key-bag": "wireguard-server",
|
||||
"preshared-key": "psk-server",
|
||||
"endpoint": "2001:db8:3c4d:20::1",
|
||||
"endpoint-port": 51820,
|
||||
"allowed-ips": ["10.0.0.1/32", "10.0.0.2/32", "192.168.1.0/24", "fd00:0::1/128", "fd00:0::2/128", "2001:db8:3c4d:01::/64"],
|
||||
"persistent-keepalive": 5
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ietf-routing": {
|
||||
"routing": {
|
||||
"control-plane-protocols": {
|
||||
"control-plane-protocol": [{
|
||||
"type": "infix-routing:static",
|
||||
"name": "default",
|
||||
"static-routes": {
|
||||
"ipv4": {
|
||||
"route": [{
|
||||
"destination-prefix": "10.0.0.0/24",
|
||||
"next-hop": {
|
||||
"next-hop-address": "10.0.0.1"
|
||||
}
|
||||
}, {
|
||||
"destination-prefix": "192.168.0.0/16",
|
||||
"next-hop": {
|
||||
"next-hop-address": "10.0.0.1"
|
||||
}
|
||||
}]
|
||||
},
|
||||
"ipv6": {
|
||||
"route": [{
|
||||
"destination-prefix": "fd00::/64",
|
||||
"next-hop": {
|
||||
"next-hop-address": "fd00::1"
|
||||
}
|
||||
}, {
|
||||
"destination-prefix": "2001:db8:3c4d:01::/64",
|
||||
"next-hop": {
|
||||
"next-hop-address": "fd00::1"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
with infamy.Test() as test:
|
||||
with test.step("Set up topology and attach to target DUTs"):
|
||||
env = infamy.Env()
|
||||
server = env.attach("server", "mgmt")
|
||||
client1 = env.attach("client1", "mgmt")
|
||||
client2 = env.attach("client2", "mgmt")
|
||||
|
||||
_, hclient1 = env.ltop.xlate("host", "data1")
|
||||
_, hserver = env.ltop.xlate("host", "data2")
|
||||
|
||||
with test.step("Configure server, client1 and client2"):
|
||||
util.parallel(configure_server(server), configure_client1(client1), configure_client2(client2))
|
||||
|
||||
with infamy.IsolatedMacVlan(hserver) as nsserver, infamy.IsolatedMacVlan(hclient1) as nsclient1:
|
||||
nsserver.addip("192.168.0.1")
|
||||
nsserver.addroute("default", "192.168.0.2");
|
||||
nsclient1.addip("192.168.1.1")
|
||||
nsclient1.addroute("default", "192.168.1.2");
|
||||
nsserver.addip("2001:db8:3c4d:02::100", prefix_length=64, proto="ipv6")
|
||||
nsserver.addroute("default", "2001:db8:3c4d:02::2", proto="ipv6")
|
||||
nsclient1.addip("2001:db8:3c4d:01::100", prefix_length=64, proto="ipv6")
|
||||
nsclient1.addroute("default", "2001:db8:3c4d:01::2", proto="ipv6")
|
||||
|
||||
with test.step("Verify IPv4 connectivity with ping 10.0.0.1, 10.0.0.2 and 10.0.0.3 from host:data1"):
|
||||
util.parallel(nsclient1.must_reach("10.0.0.1"),
|
||||
nsclient1.must_reach("10.0.0.2"),
|
||||
nsclient1.must_reach("10.0.0.3"))
|
||||
|
||||
with test.step("Verify IPv4 connectivity with ping 10.0.0.1 and 10.0.0.2 from host:data2"):
|
||||
util.parallel(nsserver.must_reach("10.0.0.1"),
|
||||
nsserver.must_reach("10.0.0.2"))
|
||||
|
||||
with test.step("Verify host:data2 can not ping 10.0.0.3"):
|
||||
nsserver.must_not_reach("10.0.0.3") # Not in allowed IPs
|
||||
|
||||
with test.step("Verify IPv6 connectivity with ping fd00:0::1, fd00:0::2 and fd00:0::3 from host:data1"):
|
||||
util.parallel(nsclient1.must_reach("fd00:0::1"),
|
||||
nsclient1.must_reach("fd00:0::2"),
|
||||
nsclient1.must_reach("fd00:0::3"))
|
||||
|
||||
with test.step("Verify IPv6 connectivity with ping fd00:0:1 and fd00:0:2 from host:data2"):
|
||||
util.parallel(nsserver.must_reach("fd00:0::1"),
|
||||
nsserver.must_reach("fd00:0::2"))
|
||||
|
||||
with test.step("Verify host:data2 can not ping fd00:0::3"):
|
||||
nsserver.must_not_reach("fd00:0::3") # Not in allowed IPs
|
||||
|
||||
|
||||
test.succeed()
|
||||
@@ -0,0 +1,43 @@
|
||||
graph "wireguard-multipoint" {
|
||||
layout="neato";
|
||||
overlap="false";
|
||||
esep="+40";
|
||||
|
||||
node [shape=record, fontname="DejaVu Sans Mono, Book"];
|
||||
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
|
||||
|
||||
host [
|
||||
label=" { <data1> data1 } | { <mgmt2> mgmt2 } | { <mgmt1> mgmt1 } | host | { <data2> data2 } | { <mgmt3> mgmt3 }"
|
||||
pos="6,0!",
|
||||
requires="controller",
|
||||
];
|
||||
|
||||
server [
|
||||
label=" { <link1> link1 } | { server } | { <mgmt> mgmt } | { <data> data } | { <link2> link2 }"
|
||||
pos="6, -6!",
|
||||
requires="infix",
|
||||
];
|
||||
|
||||
client1 [
|
||||
label="{ { <data> data } | { <mgmt> mgmt } | { client1 } | <link> link } ",
|
||||
pos="0, -6!",
|
||||
requires="infix",
|
||||
];
|
||||
|
||||
client2 [
|
||||
label="{ { <data> data } | { <mgmt> mgmt } | { client2 } | <link> link } ",
|
||||
pos="12,-6!",
|
||||
requires="infix",
|
||||
];
|
||||
|
||||
host:mgmt1 -- server:mgmt [requires="mgmt", color="lightgray"]
|
||||
host:mgmt2 -- client1:mgmt [requires="mgmt", color="lightgray"]
|
||||
host:mgmt3 -- client2:mgmt [requires="mgmt", color="lightgray"]
|
||||
|
||||
host:data1 -- client1:data [headlabel=".1", label="192.168.1.0/24" taillabel=".2 ", labeldistance=1, fontcolor="black", color="black"]
|
||||
host:data2 -- server:data [headlabel=".1", label="192.168.0.0/24" taillabel=".2 ", labeldistance=1, fontcolor="black", color="black"]
|
||||
|
||||
server:link1 -- client1:link [headlabel=".1", label="192.168.10.0/24", taillabel=".10 ", labeldistance=1, fontcolor="black", color="black"]
|
||||
server:link2 -- client2:link [headlabel=".2\n\n", label="192.168.20.0/24", taillabel="\n.20", labeldistance=1, fontcolor="black", color="black"]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<!-- Title: wireguard-multipoint Pages: 1 -->
|
||||
<svg width="638pt" height="351pt"
|
||||
viewBox="0.00 0.00 638.06 351.03" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 347.03)">
|
||||
<title>wireguard-multipoint</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-347.03 634.06,-347.03 634.06,4 -4,4"/>
|
||||
<!-- host -->
|
||||
<g id="node1" class="node">
|
||||
<title>host</title>
|
||||
<polygon fill="none" stroke="black" points="145.03,-306.53 145.03,-342.53 485.03,-342.53 485.03,-306.53 145.03,-306.53"/>
|
||||
<text text-anchor="middle" x="174.03" y="-320.83" font-family="DejaVu Sans Mono, Book" font-size="14.00">data1</text>
|
||||
<polyline fill="none" stroke="black" points="203.03,-306.53 203.03,-342.53 "/>
|
||||
<text text-anchor="middle" x="232.03" y="-320.83" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt2</text>
|
||||
<polyline fill="none" stroke="black" points="261.03,-306.53 261.03,-342.53 "/>
|
||||
<text text-anchor="middle" x="290.03" y="-320.83" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
|
||||
<polyline fill="none" stroke="black" points="319.03,-306.53 319.03,-342.53 "/>
|
||||
<text text-anchor="middle" x="344.03" y="-320.83" font-family="DejaVu Sans Mono, Book" font-size="14.00">host</text>
|
||||
<polyline fill="none" stroke="black" points="369.03,-306.53 369.03,-342.53 "/>
|
||||
<text text-anchor="middle" x="398.03" y="-320.83" font-family="DejaVu Sans Mono, Book" font-size="14.00">data2</text>
|
||||
<polyline fill="none" stroke="black" points="427.03,-306.53 427.03,-342.53 "/>
|
||||
<text text-anchor="middle" x="456.03" y="-320.83" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt3</text>
|
||||
</g>
|
||||
<!-- server -->
|
||||
<g id="node2" class="node">
|
||||
<title>server</title>
|
||||
<polygon fill="none" stroke="black" points="174.03,-28.5 174.03,-64.5 456.03,-64.5 456.03,-28.5 174.03,-28.5"/>
|
||||
<text text-anchor="middle" x="203.03" y="-42.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">link1</text>
|
||||
<polyline fill="none" stroke="black" points="232.03,-28.5 232.03,-64.5 "/>
|
||||
<text text-anchor="middle" x="265.03" y="-42.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">server</text>
|
||||
<polyline fill="none" stroke="black" points="298.03,-28.5 298.03,-64.5 "/>
|
||||
<text text-anchor="middle" x="323.03" y="-42.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="348.03,-28.5 348.03,-64.5 "/>
|
||||
<text text-anchor="middle" x="373.03" y="-42.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
|
||||
<polyline fill="none" stroke="black" points="398.03,-28.5 398.03,-64.5 "/>
|
||||
<text text-anchor="middle" x="427.03" y="-42.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">link2</text>
|
||||
</g>
|
||||
<!-- host--server -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>host:mgmt1--server:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M290.03,-306.53C290.03,-306.53 323.03,-64.5 323.03,-64.5"/>
|
||||
</g>
|
||||
<!-- host--server -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>host:data2--server:data</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M398.03,-306.53C398.03,-306.53 373.03,-64.5 373.03,-64.5"/>
|
||||
<text text-anchor="middle" x="331.03" y="-189.31" font-family="DejaVu Serif, Book" font-size="14.00">192.168.0.0/24</text>
|
||||
<text text-anchor="middle" x="378.16" y="-69.38" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
<text text-anchor="middle" x="392.89" y="-294.25" font-family="DejaVu Serif, Book" font-size="14.00">.2 </text>
|
||||
</g>
|
||||
<!-- client1 -->
|
||||
<g id="node3" class="node">
|
||||
<title>client1</title>
|
||||
<polygon fill="none" stroke="black" points="0,-0.5 0,-92.5 74,-92.5 74,-0.5 0,-0.5"/>
|
||||
<text text-anchor="middle" x="37" y="-77.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
|
||||
<polyline fill="none" stroke="black" points="0,-69.5 74,-69.5 "/>
|
||||
<text text-anchor="middle" x="37" y="-54.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="0,-46.5 74,-46.5 "/>
|
||||
<text text-anchor="middle" x="37" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">client1</text>
|
||||
<polyline fill="none" stroke="black" points="0,-23.5 74,-23.5 "/>
|
||||
<text text-anchor="middle" x="37" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
|
||||
</g>
|
||||
<!-- host--client1 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>host:mgmt2--client1:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M232.03,-306.53C232.03,-306.53 74,-58.5 74,-58.5"/>
|
||||
</g>
|
||||
<!-- host--client1 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>host:data1--client1:data</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M174.03,-306.53C174.03,-306.53 74,-81.5 74,-81.5"/>
|
||||
<text text-anchor="middle" x="69.51" y="-197.81" font-family="DejaVu Serif, Book" font-size="14.00">192.168.1.0/24</text>
|
||||
<text text-anchor="middle" x="81.54" y="-84.37" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
<text text-anchor="middle" x="166.48" y="-296.26" font-family="DejaVu Serif, Book" font-size="14.00">.2 </text>
|
||||
</g>
|
||||
<!-- client2 -->
|
||||
<g id="node4" class="node">
|
||||
<title>client2</title>
|
||||
<polygon fill="none" stroke="black" points="556.06,-0.5 556.06,-92.5 630.06,-92.5 630.06,-0.5 556.06,-0.5"/>
|
||||
<text text-anchor="middle" x="593.06" y="-77.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
|
||||
<polyline fill="none" stroke="black" points="556.06,-69.5 630.06,-69.5 "/>
|
||||
<text text-anchor="middle" x="593.06" y="-54.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="556.06,-46.5 630.06,-46.5 "/>
|
||||
<text text-anchor="middle" x="593.06" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">client2</text>
|
||||
<polyline fill="none" stroke="black" points="556.06,-23.5 630.06,-23.5 "/>
|
||||
<text text-anchor="middle" x="593.06" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
|
||||
</g>
|
||||
<!-- host--client2 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>host:mgmt3--client2:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M456.03,-306.53C456.03,-306.53 556.06,-58.5 556.06,-58.5"/>
|
||||
</g>
|
||||
<!-- server--client1 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>server:link1--client1:link</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M174.03,-46.5C174.03,-46.5 74,-11.5 74,-11.5"/>
|
||||
<text text-anchor="middle" x="153.51" y="-17.8" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.0/24</text>
|
||||
<text text-anchor="middle" x="83.95" y="-6.8" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
<text text-anchor="middle" x="164.08" y="-43.8" font-family="DejaVu Serif, Book" font-size="14.00">.10 </text>
|
||||
</g>
|
||||
<!-- server--client2 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>server:link2--client2:link</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M456.03,-46.5C456.03,-46.5 556.06,-11.5 556.06,-11.5"/>
|
||||
<text text-anchor="middle" x="447.04" y="-17.8" font-family="DejaVu Serif, Book" font-size="14.00">192.168.20.0/24</text>
|
||||
<text text-anchor="middle" x="548.9" y="-22.78" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
|
||||
<text text-anchor="middle" x="463.19" y="-27.82" font-family="DejaVu Serif, Book" font-size="14.00">.20</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.4 KiB |
@@ -0,0 +1 @@
|
||||
test.adoc
|
||||
@@ -0,0 +1,45 @@
|
||||
=== WireGuard Point-to-Point
|
||||
|
||||
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/interfaces/wireguard_p2p]
|
||||
|
||||
==== Description
|
||||
|
||||
Set up a WireGuard tunnel between two DUTs with a host connected to the first
|
||||
DUT. Enable IP forwarding on first DUT's interface to host and the WireGuard
|
||||
tunnel interface to the second DUT. On host, add route to IP network of second
|
||||
DUT and verify connectivity with the second DUT through the WireGuard tunnel.
|
||||
|
||||
This test verifies:
|
||||
|
||||
- WireGuard tunnel establishment between two peers
|
||||
- Key management via ietf-keystore with X25519 keypairs
|
||||
- IPv4 and IPv6 connectivity through the encrypted tunnel
|
||||
- Proper routing through the WireGuard tunnel
|
||||
|
||||
Topology:
|
||||
....
|
||||
192.168.50.0/24
|
||||
host:data ---- left:data left:link ---- right:link
|
||||
192.168.10.2/24 192.168.10.1 192.168.50.1 192.168.50.2
|
||||
\\ /
|
||||
\\ /
|
||||
\\ WireGuard
|
||||
\\ Tunnel /
|
||||
\\ /
|
||||
left:wg0 right:wg0
|
||||
10.0.0.1/32 10.0.0.2/32
|
||||
|
||||
....
|
||||
|
||||
==== Topology
|
||||
|
||||
image::topology.svg[WireGuard Point-to-Point topology, align=center, scaledwidth=75%]
|
||||
|
||||
==== Sequence
|
||||
|
||||
. Set up topology and attach to target DUTs
|
||||
. Configure WireGuard tunnel on DUTs
|
||||
. Verify IPv4 connectivity with ping 10.0.0.2 from host:data
|
||||
. Verify IPv6 connectivity with ping fd00::2 from host:data
|
||||
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
#!/usr/bin/env python3
|
||||
r"""
|
||||
Basic WireGuard point-to-point tunnel test
|
||||
|
||||
Set up a WireGuard tunnel between two DUTs with a host connected to the first
|
||||
DUT. Enable IP forwarding on first DUT's interface to host and the WireGuard
|
||||
tunnel interface to the second DUT. On host, add route to IP network of second
|
||||
DUT and verify connectivity with the second DUT through the WireGuard tunnel.
|
||||
|
||||
This test verifies:
|
||||
|
||||
- WireGuard tunnel establishment between two peers
|
||||
- Key management via ietf-keystore with X25519 keypairs
|
||||
- IPv4 and IPv6 connectivity through the encrypted tunnel
|
||||
- Proper routing through the WireGuard tunnel
|
||||
|
||||
Topology:
|
||||
....
|
||||
192.168.50.0/24
|
||||
host:data ---- left:data left:link ---- right:link
|
||||
192.168.10.2/24 192.168.10.1 192.168.50.1 192.168.50.2
|
||||
\\ /
|
||||
\\ /
|
||||
\\ WireGuard
|
||||
\\ Tunnel /
|
||||
\\ /
|
||||
left:wg0 right:wg0
|
||||
10.0.0.1/32 10.0.0.2/32
|
||||
|
||||
....
|
||||
|
||||
"""
|
||||
|
||||
import infamy
|
||||
import infamy.util as util
|
||||
|
||||
left_private_key = "EJPoi0BnccsfjEhKk0IWwNzJKXZKgS6XaKt+InYITVA="
|
||||
left_public_key = "xWVOEFUZZ5VI6t1fhZeISNyw7Ma/bY8INzIoaSSLlz8="
|
||||
|
||||
right_private_key = "UEaX13FTGhiIrnnKRd20KWh/vG6zqRIMSTzOP3hNs2s="
|
||||
right_public_key = "2pytpunN+e3V9e5asMXP+UqKoerFm08KWzcFYoWP41k="
|
||||
|
||||
with infamy.Test() as test:
|
||||
with test.step("Set up topology and attach to target DUTs"):
|
||||
env = infamy.Env()
|
||||
left = env.attach("left", "mgmt")
|
||||
right = env.attach("right", "mgmt")
|
||||
|
||||
with test.step("Configure WireGuard tunnel on DUTs"):
|
||||
util.parallel(left.put_config_dicts({
|
||||
"ietf-keystore": {
|
||||
"keystore": {
|
||||
"asymmetric-keys": {
|
||||
"asymmetric-key": [{
|
||||
"name": "left-wg-key",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": left_public_key,
|
||||
"private-key-format": "infix-crypto-types:x25519-private-key-format",
|
||||
"cleartext-private-key": left_private_key
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-truststore": {
|
||||
"truststore": {
|
||||
"public-key-bags": {
|
||||
"public-key-bag": [{
|
||||
"name": "wireguard-peers",
|
||||
"public-key": [{
|
||||
"name": "right-wg-pubkey",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": right_public_key
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-interfaces": {
|
||||
"interfaces": {
|
||||
"interface": [{
|
||||
"name": left["link"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.50.1",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "2001:db8:3c4d:50::1",
|
||||
"prefix-length": 64
|
||||
}],
|
||||
"forwarding": True
|
||||
}
|
||||
}, {
|
||||
"name": left["data"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.10.1",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "2001:db8:3c4d:10::1",
|
||||
"prefix-length": 64
|
||||
}],
|
||||
"forwarding": True
|
||||
}
|
||||
}, {
|
||||
"name": "wg0",
|
||||
"type": "infix-if-type:wireguard",
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "10.0.0.1",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "fd00::1",
|
||||
"prefix-length": 64
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"wireguard": {
|
||||
"listen-port": 51820,
|
||||
"private-key": "left-wg-key",
|
||||
"peers": [{
|
||||
"public-key-bag": "wireguard-peers",
|
||||
"endpoint": "192.168.50.2",
|
||||
"endpoint-port": 51820,
|
||||
"allowed-ips": ["10.0.0.0/24", "fd00::/64"]
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}),
|
||||
right.put_config_dicts({
|
||||
"ietf-keystore": {
|
||||
"keystore": {
|
||||
"asymmetric-keys": {
|
||||
"asymmetric-key": [{
|
||||
"name": "right-wg-key",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": right_public_key,
|
||||
"private-key-format": "infix-crypto-types:x25519-private-key-format",
|
||||
"cleartext-private-key": right_private_key
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-truststore": {
|
||||
"truststore": {
|
||||
"public-key-bags": {
|
||||
"public-key-bag": [{
|
||||
"name": "wireguard-peers",
|
||||
"public-key": [{
|
||||
"name": "left-wg-pubkey",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": left_public_key
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-interfaces": {
|
||||
"interfaces": {
|
||||
"interface": [{
|
||||
"name": right["link"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.50.2",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "2001:db8:3c4d:50::2",
|
||||
"prefix-length": 64
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
"name": "wg0",
|
||||
"type": "infix-if-type:wireguard",
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "10.0.0.2",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"ipv6": {
|
||||
"address": [{
|
||||
"ip": "fd00::2",
|
||||
"prefix-length": 64
|
||||
}]
|
||||
},
|
||||
"wireguard": {
|
||||
"listen-port": 51820,
|
||||
"private-key": "right-wg-key",
|
||||
"peers": [{
|
||||
"public-key-bag": "wireguard-peers",
|
||||
"endpoint": "192.168.50.1",
|
||||
"endpoint-port": 51820,
|
||||
"allowed-ips": ["10.0.0.0/24", "fd00::/64", "2001:db8:3c4d:10::/64", "192.168.10.0/24"]
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ietf-routing": {
|
||||
"routing": {
|
||||
"control-plane-protocols": {
|
||||
"control-plane-protocol": [{
|
||||
"type": "infix-routing:static",
|
||||
"name": "default",
|
||||
"static-routes": {
|
||||
"ipv4": {
|
||||
"route": [{
|
||||
"destination-prefix": "192.168.10.0/24",
|
||||
"next-hop": {
|
||||
"next-hop-address": "10.0.0.1"
|
||||
}
|
||||
}]
|
||||
},
|
||||
"ipv6": {
|
||||
"route": [{
|
||||
"destination-prefix": "2001:db8:3c4d:10::/64",
|
||||
"next-hop": {
|
||||
"next-hop-address": "fd00::1"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
_, hport = env.ltop.xlate("host", "data")
|
||||
with test.step("Verify IPv4 connectivity with ping 10.0.0.2 from host:data"):
|
||||
with infamy.IsolatedMacVlan(hport) as ns0:
|
||||
ns0.addip("192.168.10.2")
|
||||
ns0.addroute("10.0.0.0/24", "192.168.10.1")
|
||||
ns0.must_reach("10.0.0.2")
|
||||
|
||||
with test.step("Verify IPv6 connectivity with ping fd00::2 from host:data"):
|
||||
with infamy.IsolatedMacVlan(hport) as ns0:
|
||||
ns0.addip("2001:db8:3c4d:10::2", prefix_length=64, proto="ipv6")
|
||||
ns0.addroute("fd00::/64", "2001:db8:3c4d:10::1", proto="ipv6")
|
||||
ns0.must_reach("fd00::2")
|
||||
|
||||
test.succeed()
|
||||
@@ -0,0 +1,34 @@
|
||||
graph "wireguard-basic" {
|
||||
layout="neato";
|
||||
overlap="false";
|
||||
esep="+40";
|
||||
|
||||
node [shape=record, fontname="DejaVu Sans Mono, Book"];
|
||||
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
|
||||
|
||||
host [
|
||||
label="host | { <mgmt1> mgmt1 } | { <data> data } | { <mgmt2> mgmt2 }"
|
||||
pos="3,0!",
|
||||
requires="controller",
|
||||
];
|
||||
|
||||
left [
|
||||
label="{ left } | { <mgmt> mgmt } | { <data> data } | { <link> link }",
|
||||
pos="0, -3!",
|
||||
|
||||
requires="infix",
|
||||
];
|
||||
|
||||
right [
|
||||
label="{ <link> link } | { <mgmt> mgmt } | { right }",
|
||||
pos="8,-3!",
|
||||
|
||||
requires="infix",
|
||||
];
|
||||
|
||||
host:mgmt1 -- left:mgmt [requires="mgmt", color="lightgray"]
|
||||
host:data -- left:data [headlabel=".1", label="192.168.10.0/24" taillabel=".2 ", labeldistance=1, fontcolor="black", color="black"]
|
||||
host:mgmt2 -- right:mgmt [requires="mgmt", color="lightgray"]
|
||||
|
||||
left:link -- right:link [headlabel=".1\n\n", label="192.168.50.0/24", taillabel="\n.2", labeldistance=1, fontcolor="black", color="black"]
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<!-- Title: wireguard-basic Pages: 1 -->
|
||||
<svg width="552pt" height="183pt"
|
||||
viewBox="0.00 0.00 552.37 183.24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 179.24)">
|
||||
<title>wireguard-basic</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-179.24 548.37,-179.24 548.37,4 -4,4"/>
|
||||
<!-- host -->
|
||||
<g id="node1" class="node">
|
||||
<title>host</title>
|
||||
<polygon fill="none" stroke="black" points="129.01,-138.74 129.01,-174.74 345.01,-174.74 345.01,-138.74 129.01,-138.74"/>
|
||||
<text text-anchor="middle" x="154.01" y="-153.04" font-family="DejaVu Sans Mono, Book" font-size="14.00">host</text>
|
||||
<polyline fill="none" stroke="black" points="179.01,-138.74 179.01,-174.74 "/>
|
||||
<text text-anchor="middle" x="208.01" y="-153.04" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
|
||||
<polyline fill="none" stroke="black" points="237.01,-138.74 237.01,-174.74 "/>
|
||||
<text text-anchor="middle" x="262.01" y="-153.04" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
|
||||
<polyline fill="none" stroke="black" points="287.01,-138.74 287.01,-174.74 "/>
|
||||
<text text-anchor="middle" x="316.01" y="-153.04" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt2</text>
|
||||
</g>
|
||||
<!-- left -->
|
||||
<g id="node2" class="node">
|
||||
<title>left</title>
|
||||
<polygon fill="none" stroke="black" points="0,-1.73 0,-37.73 200,-37.73 200,-1.73 0,-1.73"/>
|
||||
<text text-anchor="middle" x="25" y="-16.03" font-family="DejaVu Sans Mono, Book" font-size="14.00">left</text>
|
||||
<polyline fill="none" stroke="black" points="50,-1.73 50,-37.73 "/>
|
||||
<text text-anchor="middle" x="75" y="-16.03" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="100,-1.73 100,-37.73 "/>
|
||||
<text text-anchor="middle" x="125" y="-16.03" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
|
||||
<polyline fill="none" stroke="black" points="150,-1.73 150,-37.73 "/>
|
||||
<text text-anchor="middle" x="175" y="-16.03" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
|
||||
</g>
|
||||
<!-- host--left -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>host:mgmt1--left:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M208.01,-138.74C208.01,-138.74 75,-37.73 75,-37.73"/>
|
||||
</g>
|
||||
<!-- host--left -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>host:data--left:data</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M262.01,-138.74C262.01,-138.74 125,-37.73 125,-37.73"/>
|
||||
<text text-anchor="middle" x="134.51" y="-92.03" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.0/24</text>
|
||||
<text text-anchor="middle" x="134.8" y="-36" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
<text text-anchor="middle" x="252.21" y="-133.06" font-family="DejaVu Serif, Book" font-size="14.00">.2 </text>
|
||||
</g>
|
||||
<!-- right -->
|
||||
<g id="node3" class="node">
|
||||
<title>right</title>
|
||||
<polygon fill="none" stroke="black" points="386.37,-1.73 386.37,-37.73 544.37,-37.73 544.37,-1.73 386.37,-1.73"/>
|
||||
<text text-anchor="middle" x="411.37" y="-16.03" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
|
||||
<polyline fill="none" stroke="black" points="436.37,-1.73 436.37,-37.73 "/>
|
||||
<text text-anchor="middle" x="461.37" y="-16.03" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="486.37,-1.73 486.37,-37.73 "/>
|
||||
<text text-anchor="middle" x="515.37" y="-16.03" font-family="DejaVu Sans Mono, Book" font-size="14.00">right</text>
|
||||
</g>
|
||||
<!-- host--right -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>host:mgmt2--right:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M345.01,-156.74C345.01,-156.74 461.37,-37.73 461.37,-37.73"/>
|
||||
</g>
|
||||
<!-- left--right -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>left:link--right:link</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M200,-19.73C200,-19.73 386.37,-19.73 386.37,-19.73"/>
|
||||
<text text-anchor="middle" x="293.18" y="-8.53" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.0/24</text>
|
||||
<text text-anchor="middle" x="377.31" y="-28.25" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
<text text-anchor="middle" x="209.06" y="-3.8" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1 @@
|
||||
test.adoc
|
||||
@@ -0,0 +1,56 @@
|
||||
=== WireGuard Roadwarrior
|
||||
|
||||
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/interfaces/wireguard_roadwarrior]
|
||||
|
||||
==== Description
|
||||
|
||||
This test demonstrates a realistic roadwarrior scenario where clients
|
||||
connect through an internet router to reach a VPN server.
|
||||
|
||||
Set up a WireGuard server with 2 roadwarrior clients connecting through
|
||||
a router that simulates the internet. Each client is on a different subnet
|
||||
behind the router, and has a private network that should be accessible
|
||||
through the VPN tunnel.
|
||||
|
||||
This test verifies:
|
||||
|
||||
- WireGuard tunnel establishment through an intermediate router
|
||||
- Roadwarrior clients on different subnets
|
||||
- Access to server's private network through the VPN tunnel
|
||||
- Routing between client networks and server network via WireGuard
|
||||
|
||||
Topology:
|
||||
....
|
||||
Server ---- Router ---- Client1
|
||||
(VPN) (Internet) \---- Client2
|
||||
|
||||
WAN: 192.168.100.0/24
|
||||
Server: 192.168.100.1
|
||||
Router: 192.168.100.2
|
||||
|
||||
Client1 link: 192.168.50.0/24 (Router LAN1)
|
||||
Client2 link: 192.168.51.0/24 (Router LAN2)
|
||||
|
||||
WireGuard tunnel: 10.0.0.0/24
|
||||
Server: 10.0.0.1/24
|
||||
Client1: 10.0.0.2/24
|
||||
Client2: 10.0.0.3/24
|
||||
|
||||
Backend networks:
|
||||
Server data: 192.168.0.0/24
|
||||
Client1 data: 192.168.1.0/24
|
||||
Client2 data: 192.168.2.0/24
|
||||
....
|
||||
|
||||
==== Topology
|
||||
|
||||
image::topology.svg[WireGuard Roadwarrior topology, align=center, scaledwidth=75%]
|
||||
|
||||
==== Sequence
|
||||
|
||||
. Set up topology and attach to target DUTs
|
||||
. Configure DUTs
|
||||
. Check on the server that both clients is connected
|
||||
. Verify IPv4 connectivity with ping 192.168.0.2 from host:data1 and host:data2
|
||||
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
#!/usr/bin/env python3
|
||||
r"""
|
||||
WireGuard roadwarrior test with router simulating internet
|
||||
|
||||
This test demonstrates a realistic roadwarrior scenario where clients
|
||||
connect through an internet router to reach a VPN server.
|
||||
|
||||
Set up a WireGuard server with 2 roadwarrior clients connecting through
|
||||
a router that simulates the internet. Each client is on a different subnet
|
||||
behind the router, and has a private network that should be accessible
|
||||
through the VPN tunnel.
|
||||
|
||||
This test verifies:
|
||||
|
||||
- WireGuard tunnel establishment through an intermediate router
|
||||
- Roadwarrior clients on different subnets
|
||||
- Access to server's private network through the VPN tunnel
|
||||
- Routing between client networks and server network via WireGuard
|
||||
|
||||
Topology:
|
||||
....
|
||||
Server ---- Router ---- Client1
|
||||
(VPN) (Internet) \---- Client2
|
||||
|
||||
WAN: 192.168.100.0/24
|
||||
Server: 192.168.100.1
|
||||
Router: 192.168.100.2
|
||||
|
||||
Client1 link: 192.168.50.0/24 (Router LAN1)
|
||||
Client2 link: 192.168.51.0/24 (Router LAN2)
|
||||
|
||||
WireGuard tunnel: 10.0.0.0/24
|
||||
Server: 10.0.0.1/24
|
||||
Client1: 10.0.0.2/24
|
||||
Client2: 10.0.0.3/24
|
||||
|
||||
Backend networks:
|
||||
Server data: 192.168.0.0/24
|
||||
Client1 data: 192.168.1.0/24
|
||||
Client2 data: 192.168.2.0/24
|
||||
....
|
||||
|
||||
"""
|
||||
|
||||
import infamy
|
||||
import infamy.util as util
|
||||
import infamy.iface as iface
|
||||
import infamy.wireguard as wg
|
||||
|
||||
def configure_server(server, server_public_key, server_private_key, client1_public_key, client2_public_key):
|
||||
"""Configure WireGuard server with key-bag level settings for all clients"""
|
||||
server.put_config_dicts({
|
||||
"ietf-keystore": {
|
||||
"keystore": {
|
||||
"asymmetric-keys": {
|
||||
"asymmetric-key": [{
|
||||
"name": "server-wg-key",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": server_public_key,
|
||||
"private-key-format": "infix-crypto-types:x25519-private-key-format",
|
||||
"cleartext-private-key": server_private_key
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-truststore": {
|
||||
"truststore": {
|
||||
"public-key-bags": {
|
||||
"public-key-bag": [{
|
||||
"name": "roadwarriors",
|
||||
"public-key": [{
|
||||
"name": "client1-key",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": client1_public_key,
|
||||
}, {
|
||||
"name": "client2-key",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": client2_public_key,
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-interfaces": {
|
||||
"interfaces": {
|
||||
"interface": [{
|
||||
"name": server["wan"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.100.1",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
}
|
||||
}, {
|
||||
"name": server["data"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.0.1",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "wg0",
|
||||
"type": "infix-if-type:wireguard",
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "10.0.0.1",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"wireguard": {
|
||||
"private-key": "server-wg-key",
|
||||
"peers": [{
|
||||
"public-key-bag": "roadwarriors",
|
||||
"persistent-keepalive": 3,
|
||||
"peer": [{
|
||||
"public-key": "client1-key",
|
||||
"allowed-ips": ["10.0.0.2/32", "192.168.1.0/24"]
|
||||
}, {
|
||||
"public-key": "client2-key",
|
||||
"allowed-ips": ["10.0.0.3/32", "192.168.2.0/24"]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ietf-routing": {
|
||||
"routing": {
|
||||
"control-plane-protocols": {
|
||||
"control-plane-protocol": [{
|
||||
"type": "infix-routing:static",
|
||||
"name": "default",
|
||||
"static-routes": {
|
||||
"ipv4": {
|
||||
"route": [{
|
||||
"destination-prefix": "192.168.1.0/24",
|
||||
"next-hop": {
|
||||
"next-hop-address": "10.0.0.2"
|
||||
}
|
||||
}, {
|
||||
"destination-prefix": "192.168.2.0/24",
|
||||
"next-hop": {
|
||||
"next-hop-address": "10.0.0.3"
|
||||
}
|
||||
}, {
|
||||
"destination-prefix": "192.168.50.0/24",
|
||||
"next-hop": {
|
||||
"next-hop-address": "192.168.100.2"
|
||||
}
|
||||
}, {
|
||||
"destination-prefix": "192.168.51.0/24",
|
||||
"next-hop": {
|
||||
"next-hop-address": "192.168.100.2"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
def configure_router(router):
|
||||
"""Configure router to forward traffic between server and clients"""
|
||||
router.put_config_dicts({
|
||||
"ietf-interfaces": {
|
||||
"interfaces": {
|
||||
"interface": [{
|
||||
"name": router["wan"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.100.2",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
}
|
||||
}, {
|
||||
"name": router["lan1"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.50.1",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
}
|
||||
}, {
|
||||
"name": router["lan2"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": "192.168.51.1",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
def configure_client(client, client_num, private_key, public_key, server_pubkey):
|
||||
"""Configure a WireGuard roadwarrior client"""
|
||||
# Client1 is on 192.168.50.0/24, Client2 is on 192.168.51.0/24
|
||||
link_subnet = 49 + client_num
|
||||
|
||||
client.put_config_dicts({
|
||||
"ietf-keystore": {
|
||||
"keystore": {
|
||||
"asymmetric-keys": {
|
||||
"asymmetric-key": [{
|
||||
"name": f"client{client_num}-wg-key",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": public_key,
|
||||
"private-key-format": "infix-crypto-types:x25519-private-key-format",
|
||||
"cleartext-private-key": private_key
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-truststore": {
|
||||
"truststore": {
|
||||
"public-key-bags": {
|
||||
"public-key-bag": [{
|
||||
"name": "server",
|
||||
"public-key": [{
|
||||
"name": "server-key",
|
||||
"public-key-format": "infix-crypto-types:x25519-public-key-format",
|
||||
"public-key": server_pubkey
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ietf-interfaces": {
|
||||
"interfaces": {
|
||||
"interface": [{
|
||||
"name": client["link"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": f"192.168.{link_subnet}.2",
|
||||
"prefix-length": 24
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
"name": client["data"],
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": f"192.168.{client_num}.1",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
}
|
||||
}, {
|
||||
"name": "wg0",
|
||||
"type": "infix-if-type:wireguard",
|
||||
"ipv4": {
|
||||
"address": [{
|
||||
"ip": f"10.0.0.{client_num + 1}",
|
||||
"prefix-length": 24
|
||||
}],
|
||||
"forwarding": True
|
||||
},
|
||||
"wireguard": {
|
||||
"private-key": f"client{client_num}-wg-key",
|
||||
"peers": [{
|
||||
"public-key-bag": "server",
|
||||
"endpoint": "192.168.100.1",
|
||||
"endpoint-port": 51820,
|
||||
"allowed-ips": ["10.0.0.0/24", "192.168.0.0/24"],
|
||||
"persistent-keepalive": 3
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ietf-routing": {
|
||||
"routing": {
|
||||
"control-plane-protocols": {
|
||||
"control-plane-protocol": [{
|
||||
"type": "infix-routing:static",
|
||||
"name": "default",
|
||||
"static-routes": {
|
||||
"ipv4": {
|
||||
"route": [{
|
||||
"destination-prefix": "192.168.0.0/24",
|
||||
"next-hop": {
|
||||
"next-hop-address": "10.0.0.1"
|
||||
}
|
||||
}, {
|
||||
"destination-prefix": "0.0.0.0/0",
|
||||
"next-hop": {
|
||||
"next-hop-address": f"192.168.{link_subnet}.1"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
server_private_key = "uIUL4AnD5QaVrwHDPHJzQ7sIQ+Q3zDdflnvfd59qa28="
|
||||
server_public_key = "qGVmu5UbNtMuZs2t9wFoOoHlvgmV+A1SyQacVb/bEV0="
|
||||
|
||||
client1_private_key = "kNmkNlSkSh9+Va2tmFv9Va8TBCZlTBF0fKAGJf8vomo="
|
||||
client1_public_key = "ROaZyvJc5DzA2XUAAeTj2YlwDsy2w0lr3t+rWj2imAk="
|
||||
|
||||
client2_private_key = "OPT7v/l5zICEmFIrO0U+YwA+w07l8Xo2Dp38hjGOHGY="
|
||||
client2_public_key = "Om9CPLYdK3l93GauKrq5WXo/gbcD+1CeqFpobRLLkB4="
|
||||
|
||||
|
||||
with infamy.Test() as test:
|
||||
with test.step("Set up topology and attach to target DUTs"):
|
||||
env = infamy.Env()
|
||||
server = env.attach("server", "mgmt")
|
||||
router = env.attach("router", "mgmt")
|
||||
client1 = env.attach("client1", "mgmt")
|
||||
client2 = env.attach("client2", "mgmt")
|
||||
|
||||
_, hport_server = env.ltop.xlate("host", "data")
|
||||
_, hport_client1 = env.ltop.xlate("host", "data1")
|
||||
_, hport_client2 = env.ltop.xlate("host", "data2")
|
||||
|
||||
with test.step("Configure DUTs"):
|
||||
util.parallel(
|
||||
lambda: configure_server(server, server_public_key, server_private_key, client1_public_key, client2_public_key),
|
||||
lambda: configure_router(router),
|
||||
lambda: configure_client(client1, 1, client1_private_key, client1_public_key, server_public_key),
|
||||
lambda: configure_client(client2, 2, client2_private_key, client2_public_key, server_public_key)
|
||||
)
|
||||
|
||||
with test.step("Check on the server that both clients is connected"):
|
||||
util.parallel(lambda: util.until(lambda: wg.is_peer_up(server, "wg0", client1_public_key)),
|
||||
lambda: util.until(lambda: wg.is_peer_up(server, "wg0", client2_public_key)))
|
||||
|
||||
with infamy.IsolatedMacVlan(hport_server) as ns_server, \
|
||||
infamy.IsolatedMacVlan(hport_client1) as ns_client1, \
|
||||
infamy.IsolatedMacVlan(hport_client2) as ns_client2:
|
||||
ns_server.addip("192.168.0.2")
|
||||
ns_server.addroute("default", "192.168.0.1")
|
||||
|
||||
ns_client1.addip("192.168.1.2")
|
||||
ns_client1.addroute("default", "192.168.1.1")
|
||||
|
||||
ns_client2.addip("192.168.2.2")
|
||||
ns_client2.addroute("default", "192.168.2.1")
|
||||
|
||||
with test.step("Verify IPv4 connectivity with ping 192.168.0.2 from host:data1 and host:data2"):
|
||||
util.parallel(
|
||||
lambda: ns_client1.must_reach("192.168.0.2"),
|
||||
lambda: ns_client2.must_reach("192.168.0.2")
|
||||
)
|
||||
|
||||
test.succeed()
|
||||
@@ -0,0 +1,52 @@
|
||||
graph "roadwarrior" {
|
||||
layout="neato";
|
||||
overlap=false;
|
||||
esep="+20";
|
||||
splines=true;
|
||||
|
||||
node [shape=record, fontname="DejaVu Sans Mono, Book"];
|
||||
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
|
||||
|
||||
host [
|
||||
label="{ <mgmt1> mgmt1 | <data> data } | host | { <mgmt2> mgmt2 } | { <data2> data2 | <mgmt3> mgmt3 | <data1> data1 | <mgmt4> mgmt4 }",
|
||||
pos="200,250!",
|
||||
requires="controller",
|
||||
];
|
||||
|
||||
server [
|
||||
label="{ <data> data | <mgmt> mgmt } | { server | 192.168.100.1 } | <wan> wan",
|
||||
pos="50,150!",
|
||||
requires="infix",
|
||||
];
|
||||
|
||||
router [
|
||||
label="<wan> wan | { <mgmt> mgmt | router | (internet) } | { <lan1> lan1 | <lan2> lan2 }",
|
||||
pos="200,150!",
|
||||
requires="infix",
|
||||
];
|
||||
|
||||
client1 [
|
||||
label="<link> link | { <data> data | <mgmt> mgmt } | { client1 | 192.168.50.2 }",
|
||||
pos="325,175!",
|
||||
requires="infix",
|
||||
];
|
||||
|
||||
client2 [
|
||||
label="<link> link | { <mgmt> mgmt | <data> data } | { client2 | 192.168.51.2 }",
|
||||
pos="325,125!",
|
||||
requires="infix",
|
||||
];
|
||||
|
||||
host:mgmt1 -- server:mgmt [requires="mgmt", color="lightgray"];
|
||||
host:mgmt2 -- router:mgmt [requires="mgmt", color="lightgray"];
|
||||
host:mgmt3 -- client1:mgmt [requires="mgmt", color="lightgray"];
|
||||
host:mgmt4 -- client2:mgmt [requires="mgmt", color="lightgray"];
|
||||
|
||||
server:wan -- router:wan [label="192.168.100.0/24", headlabel=".2", taillabel=".1", fontcolor="black", color="black"];
|
||||
router:lan1 -- client1:link [label="192.168.50.0/24", headlabel=".2", taillabel=".1", fontcolor="black", color="black"];
|
||||
router:lan2 -- client2:link [label="192.168.51.0/24", headlabel=".2", taillabel=".1", fontcolor="black", color="black"];
|
||||
|
||||
host:data -- server:data [headlabel=".1", label="192.168.0.0/24", taillabel=".2", labeldistance=1, fontcolor="black", color="black"];
|
||||
host:data1 -- client1:data [headlabel=".1", label="192.168.1.0/24", taillabel=".2", labeldistance=1, fontcolor="black", color="black"];
|
||||
host:data2 -- client2:data [headlabel=".1", label="192.168.2.0/24", taillabel=".2", labeldistance=1, fontcolor="black", color="black"];
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<!-- Title: roadwarrior Pages: 1 -->
|
||||
<svg width="883pt" height="398pt"
|
||||
viewBox="0.00 0.00 883.41 398.25" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 394.25)">
|
||||
<title>roadwarrior</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-394.25 879.41,-394.25 879.41,4 -4,4"/>
|
||||
<!-- host -->
|
||||
<g id="node1" class="node">
|
||||
<title>host</title>
|
||||
<polygon fill="none" stroke="black" points="351.21,-297.75 351.21,-389.75 575.21,-389.75 575.21,-297.75 351.21,-297.75"/>
|
||||
<text text-anchor="middle" x="380.21" y="-363.05" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
|
||||
<polyline fill="none" stroke="black" points="351.21,-343.75 409.21,-343.75 "/>
|
||||
<text text-anchor="middle" x="380.21" y="-317.05" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
|
||||
<polyline fill="none" stroke="black" points="409.21,-297.75 409.21,-389.75 "/>
|
||||
<text text-anchor="middle" x="434.21" y="-340.05" font-family="DejaVu Sans Mono, Book" font-size="14.00">host</text>
|
||||
<polyline fill="none" stroke="black" points="459.21,-297.75 459.21,-389.75 "/>
|
||||
<text text-anchor="middle" x="488.21" y="-340.05" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt2</text>
|
||||
<polyline fill="none" stroke="black" points="517.21,-297.75 517.21,-389.75 "/>
|
||||
<text text-anchor="middle" x="546.21" y="-374.55" font-family="DejaVu Sans Mono, Book" font-size="14.00">data2</text>
|
||||
<polyline fill="none" stroke="black" points="517.21,-366.75 575.21,-366.75 "/>
|
||||
<text text-anchor="middle" x="546.21" y="-351.55" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt3</text>
|
||||
<polyline fill="none" stroke="black" points="517.21,-343.75 575.21,-343.75 "/>
|
||||
<text text-anchor="middle" x="546.21" y="-328.55" font-family="DejaVu Sans Mono, Book" font-size="14.00">data1</text>
|
||||
<polyline fill="none" stroke="black" points="517.21,-320.75 575.21,-320.75 "/>
|
||||
<text text-anchor="middle" x="546.21" y="-305.55" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt4</text>
|
||||
</g>
|
||||
<!-- server -->
|
||||
<g id="node2" class="node">
|
||||
<title>server</title>
|
||||
<polygon fill="none" stroke="black" points="52.08,-118.33 52.08,-164.33 267.08,-164.33 267.08,-118.33 52.08,-118.33"/>
|
||||
<text text-anchor="middle" x="77.08" y="-149.13" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
|
||||
<polyline fill="none" stroke="black" points="52.08,-141.33 102.08,-141.33 "/>
|
||||
<text text-anchor="middle" x="77.08" y="-126.13" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="102.08,-118.33 102.08,-164.33 "/>
|
||||
<text text-anchor="middle" x="164.08" y="-149.13" font-family="DejaVu Sans Mono, Book" font-size="14.00">server</text>
|
||||
<polyline fill="none" stroke="black" points="102.08,-141.33 226.08,-141.33 "/>
|
||||
<text text-anchor="middle" x="164.08" y="-126.13" font-family="DejaVu Sans Mono, Book" font-size="14.00">192.168.100.1</text>
|
||||
<polyline fill="none" stroke="black" points="226.08,-118.33 226.08,-164.33 "/>
|
||||
<text text-anchor="middle" x="246.58" y="-137.63" font-family="DejaVu Sans Mono, Book" font-size="14.00">wan</text>
|
||||
</g>
|
||||
<!-- host--server -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>host:mgmt1--server:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M351.21,-366.75C351.21,-366.75 114.07,-325.63 32.08,-184.33 12.9,-151.27 0,-119.11 32.08,-98.33 50.31,-86.52 76.68,-118.3 76.68,-118.3"/>
|
||||
</g>
|
||||
<!-- host--server -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>host:data--server:data</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M351.21,-320.75C351.21,-320.75 76.58,-164.33 76.58,-164.33"/>
|
||||
<text text-anchor="middle" x="159.39" y="-246.34" font-family="DejaVu Serif, Book" font-size="14.00">192.168.0.0/24</text>
|
||||
<text text-anchor="middle" x="86.55" y="-161.44" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
<text text-anchor="middle" x="341.24" y="-316.23" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
|
||||
</g>
|
||||
<!-- router -->
|
||||
<g id="node3" class="node">
|
||||
<title>router</title>
|
||||
<polygon fill="none" stroke="black" points="368.21,-106.83 368.21,-175.83 558.21,-175.83 558.21,-106.83 368.21,-106.83"/>
|
||||
<text text-anchor="middle" x="388.71" y="-137.63" font-family="DejaVu Sans Mono, Book" font-size="14.00">wan</text>
|
||||
<polyline fill="none" stroke="black" points="409.21,-106.83 409.21,-175.83 "/>
|
||||
<text text-anchor="middle" x="458.71" y="-160.63" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="409.21,-152.83 508.21,-152.83 "/>
|
||||
<text text-anchor="middle" x="458.71" y="-137.63" font-family="DejaVu Sans Mono, Book" font-size="14.00">router</text>
|
||||
<polyline fill="none" stroke="black" points="409.21,-129.83 508.21,-129.83 "/>
|
||||
<text text-anchor="middle" x="458.71" y="-114.63" font-family="DejaVu Sans Mono, Book" font-size="14.00">(internet)</text>
|
||||
<polyline fill="none" stroke="black" points="508.21,-106.83 508.21,-175.83 "/>
|
||||
<text text-anchor="middle" x="533.21" y="-155.13" font-family="DejaVu Sans Mono, Book" font-size="14.00">lan1</text>
|
||||
<polyline fill="none" stroke="black" points="508.21,-141.83 558.21,-141.83 "/>
|
||||
<text text-anchor="middle" x="533.21" y="-120.63" font-family="DejaVu Sans Mono, Book" font-size="14.00">lan2</text>
|
||||
</g>
|
||||
<!-- host--router -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>host:mgmt2--router:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M488.21,-297.75C488.21,-297.75 458.21,-176.33 458.21,-176.33"/>
|
||||
</g>
|
||||
<!-- client1 -->
|
||||
<g id="node4" class="node">
|
||||
<title>client1</title>
|
||||
<polygon fill="none" stroke="black" points="608.23,-168.93 608.23,-214.93 824.23,-214.93 824.23,-168.93 608.23,-168.93"/>
|
||||
<text text-anchor="middle" x="633.23" y="-188.23" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
|
||||
<polyline fill="none" stroke="black" points="658.23,-168.93 658.23,-214.93 "/>
|
||||
<text text-anchor="middle" x="683.23" y="-199.73" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
|
||||
<polyline fill="none" stroke="black" points="658.23,-191.93 708.23,-191.93 "/>
|
||||
<text text-anchor="middle" x="683.23" y="-176.73" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="708.23,-168.93 708.23,-214.93 "/>
|
||||
<text text-anchor="middle" x="766.23" y="-199.73" font-family="DejaVu Sans Mono, Book" font-size="14.00">client1</text>
|
||||
<polyline fill="none" stroke="black" points="708.23,-191.93 824.23,-191.93 "/>
|
||||
<text text-anchor="middle" x="766.23" y="-176.73" font-family="DejaVu Sans Mono, Book" font-size="14.00">192.168.50.2</text>
|
||||
</g>
|
||||
<!-- host--client1 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>host:mgmt3--client1:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M575.21,-355.75C575.21,-355.75 773.03,-344.97 844.23,-234.93 865,-202.84 872.88,-174.24 844.23,-148.93 817.23,-125.07 683.32,-168.88 683.32,-168.88"/>
|
||||
</g>
|
||||
<!-- host--client1 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>host:data1--client1:data</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M575.21,-331.75C575.21,-331.75 683.23,-214.93 683.23,-214.93"/>
|
||||
<text text-anchor="middle" x="574.72" y="-277.14" font-family="DejaVu Serif, Book" font-size="14.00">192.168.1.0/24</text>
|
||||
<text text-anchor="middle" x="680.18" y="-220.75" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
<text text-anchor="middle" x="578.26" y="-318.52" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
|
||||
</g>
|
||||
<!-- client2 -->
|
||||
<g id="node5" class="node">
|
||||
<title>client2</title>
|
||||
<polygon fill="none" stroke="black" points="608.23,-67.72 608.23,-113.72 824.23,-113.72 824.23,-67.72 608.23,-67.72"/>
|
||||
<text text-anchor="middle" x="633.23" y="-87.02" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
|
||||
<polyline fill="none" stroke="black" points="658.23,-67.72 658.23,-113.72 "/>
|
||||
<text text-anchor="middle" x="683.23" y="-98.52" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="658.23,-90.72 708.23,-90.72 "/>
|
||||
<text text-anchor="middle" x="683.23" y="-75.52" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
|
||||
<polyline fill="none" stroke="black" points="708.23,-67.72 708.23,-113.72 "/>
|
||||
<text text-anchor="middle" x="766.23" y="-98.52" font-family="DejaVu Sans Mono, Book" font-size="14.00">client2</text>
|
||||
<polyline fill="none" stroke="black" points="708.23,-90.72 824.23,-90.72 "/>
|
||||
<text text-anchor="middle" x="766.23" y="-75.52" font-family="DejaVu Sans Mono, Book" font-size="14.00">192.168.51.2</text>
|
||||
</g>
|
||||
<!-- host--client2 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>host:mgmt4--client2:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M575.21,-308.75C575.21,-308.75 769.05,-333.52 844.23,-234.93 867.41,-204.54 868.2,-178.71 844.23,-148.93 832.75,-134.67 683.23,-113.72 683.23,-113.72"/>
|
||||
</g>
|
||||
<!-- host--client2 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>host:data2--client2:data</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M575.21,-378.75C575.21,-378.75 774.54,-351.22 844.23,-234.93 865.62,-199.25 875.41,-75.27 844.23,-47.72 790.23,0 683.32,-67.67 683.32,-67.67"/>
|
||||
<text text-anchor="middle" x="729.24" y="-357.4" font-family="DejaVu Serif, Book" font-size="14.00">192.168.2.0/24</text>
|
||||
<text text-anchor="middle" x="688.88" y="-55.66" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
<text text-anchor="middle" x="583.51" y="-369.47" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
|
||||
</g>
|
||||
<!-- server--router -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>server:wan--router:wan</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M267.58,-141.33C267.58,-141.33 368.21,-141.33 368.21,-141.33"/>
|
||||
<text text-anchor="middle" x="317.89" y="-130.13" font-family="DejaVu Serif, Book" font-size="14.00">192.168.100.0/24</text>
|
||||
<text text-anchor="middle" x="361.21" y="-145.13" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
|
||||
<text text-anchor="middle" x="274.58" y="-145.13" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
</g>
|
||||
<!-- router--client1 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>router:lan1--client1:link</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M558.21,-159.33C558.21,-159.33 608.23,-191.93 608.23,-191.93"/>
|
||||
<text text-anchor="middle" x="524.22" y="-179.43" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.0/24</text>
|
||||
<text text-anchor="middle" x="601.23" y="-195.73" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
|
||||
<text text-anchor="middle" x="565.21" y="-163.13" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
</g>
|
||||
<!-- router--client2 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>router:lan2--client2:link</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M558.21,-124.33C558.21,-124.33 608.23,-90.72 608.23,-90.72"/>
|
||||
<text text-anchor="middle" x="524.22" y="-96.32" font-family="DejaVu Serif, Book" font-size="14.00">192.168.51.0/24</text>
|
||||
<text text-anchor="middle" x="601.23" y="-94.52" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
|
||||
<text text-anchor="middle" x="565.21" y="-128.13" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,90 @@
|
||||
"""
|
||||
Fetch WireGuard interface status from remote device.
|
||||
"""
|
||||
import json
|
||||
|
||||
|
||||
def get_peers(target, iface):
|
||||
"""Get all WireGuard peers from interface as a list"""
|
||||
interface = target.get_iface(iface)
|
||||
if interface is None:
|
||||
return []
|
||||
|
||||
wg = interface.get("wireguard") or interface.get("infix-if-wireguard:wireguard")
|
||||
if wg is None:
|
||||
return []
|
||||
|
||||
# Peers are under 'peer-status' in operational state
|
||||
peer_status = wg.get('peer-status')
|
||||
if peer_status is None:
|
||||
return []
|
||||
|
||||
# The peer-status container has a 'peer' list inside it
|
||||
if isinstance(peer_status, dict):
|
||||
peer_list = peer_status.get('peer', [])
|
||||
if isinstance(peer_list, list):
|
||||
return peer_list
|
||||
# Single peer might not be in a list
|
||||
if peer_list:
|
||||
return [peer_list]
|
||||
return []
|
||||
|
||||
# If peer_status is already a list
|
||||
if isinstance(peer_status, list):
|
||||
return peer_status
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def get_peer_by_pubkey(target, iface, public_key):
|
||||
"""Get specific WireGuard peer by public key"""
|
||||
peers = get_peers(target, iface)
|
||||
|
||||
for peer in peers:
|
||||
if peer.get('public-key') == public_key:
|
||||
return peer
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def is_peer_up(target, iface, public_key):
|
||||
"""Check if WireGuard peer connection status is 'up'"""
|
||||
peer = get_peer_by_pubkey(target, iface, public_key)
|
||||
if peer is None:
|
||||
return False
|
||||
|
||||
status = peer.get('connection-status')
|
||||
if status is None:
|
||||
return False
|
||||
|
||||
return status.lower() == 'up'
|
||||
|
||||
|
||||
def get_peer_endpoint(target, iface, public_key):
|
||||
"""Get WireGuard peer endpoint"""
|
||||
peer = get_peer_by_pubkey(target, iface, public_key)
|
||||
if peer is None:
|
||||
return None
|
||||
|
||||
return peer.get('endpoint')
|
||||
|
||||
|
||||
def get_peer_transfer(target, iface, public_key):
|
||||
"""Get WireGuard peer transfer statistics (tx, rx in bytes)"""
|
||||
peer = get_peer_by_pubkey(target, iface, public_key)
|
||||
if peer is None:
|
||||
return None, None
|
||||
|
||||
tx = peer.get('transfer-tx')
|
||||
rx = peer.get('transfer-rx')
|
||||
|
||||
return tx, rx
|
||||
|
||||
|
||||
def get_peer_handshake(target, iface, public_key):
|
||||
"""Get WireGuard peer latest handshake timestamp"""
|
||||
peer = get_peer_by_pubkey(target, iface, public_key)
|
||||
if peer is None:
|
||||
return None
|
||||
|
||||
return peer.get('latest-handshake')
|
||||