Last active
May 24, 2024 08:48
-
-
Save yescallop/556ed8abb3042ae535f338581b471c4b to your computer and use it in GitHub Desktop.
Assigning dynamic IPv6 GUA to WireGuard interface
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[CmdletBinding(DefaultParameterSetName = 'Reresolve')] | |
param ( | |
[Parameter(Mandatory, ParameterSetName = "Stop")] | |
[switch]$Stop, | |
[Parameter(Mandatory, ParameterSetName = "Reresolve")] | |
[Parameter(Mandatory, ParameterSetName = "ReresolveAndAssignV6")] | |
[string]$Peer, | |
[Parameter(Mandatory, ParameterSetName = "Reresolve")] | |
[Parameter(Mandatory, ParameterSetName = "ReresolveAndAssignV6")] | |
[string]$DnsName, | |
[Parameter(ParameterSetName = "Reresolve")] | |
[Parameter(ParameterSetName = "ReresolveAndAssignV6")] | |
[string]$DnsType = "A_AAAA", | |
[Parameter(Mandatory, ParameterSetName = "Reresolve")] | |
[Parameter(Mandatory, ParameterSetName = "ReresolveAndAssignV6")] | |
[int]$Port, | |
[Parameter(Mandatory, ParameterSetName = "AssignV6")] | |
[Parameter(ParameterSetName = "ReresolveAndAssignV6")] | |
[string]$DnsNameV6 = $DnsName, | |
[Parameter(ParameterSetName = "AssignV6")] | |
[Parameter(ParameterSetName = "ReresolveAndAssignV6")] | |
[int]$PrefixLen = 64, | |
[Parameter(Mandatory, ParameterSetName = "AssignV6")] | |
[Parameter(Mandatory, ParameterSetName = "ReresolveAndAssignV6")] | |
[string]$Suffix, | |
[Parameter(ParameterSetName = "AssignV6")] | |
[Parameter(ParameterSetName = "ReresolveAndAssignV6")] | |
[switch]$AddDefaultRouteV6 | |
) | |
$ErrorActionPreference = "Stop" | |
$tunName = $env:WIREGUARD_TUNNEL_NAME | |
$pidFile = Join-Path $env:TEMP "wg-dynconf-$tunName.pid" | |
if ($Stop) { | |
$daemonPid = Get-Content $pidFile | |
Stop-Process -Id $daemonPid | |
Write-Output "Stopped daemon with PID $daemonPid" | |
exit | |
} | |
if ($DnsType -notin ("A_AAAA", "A", "AAAA")) { | |
Write-Output "Invalid DnsType" | |
exit 1 | |
} | |
function Ipv6AddrToBigInt { | |
param ([string]$addr) | |
$addrBytes = [ipaddress]::Parse($addr).GetAddressBytes(); | |
[array]::Reverse($addrBytes) | |
return [bigint]::New($addrBytes) | |
} | |
function BigIntToIpv6Addr { | |
param ([bigint]$addrBits) | |
$addrBytes = $addrBits.ToByteArray(); | |
[array]::Resize([ref]$addrBytes, 16); | |
[array]::Reverse($addrBytes) | |
return [ipaddress]::new($addrBytes) | |
} | |
if ($Suffix) { | |
if ($PrefixLen -lt 0 -or $PrefixLen -gt 128) { | |
Write-Output "PrefixLen must be between 0 to 128" | |
exit 1 | |
} | |
$suffixMask = ([bigint]1 -shl (128 - $PrefixLen)) - 1 | |
$prefixMask = ([bigint]1 -shl 128) - 1 - $suffixMask | |
$suffixBits = Ipv6AddrToBigInt $Suffix | |
if (($suffixBits -band $prefixMask) -ne 0) { | |
Write-Output "Invalid combination of PrefixLen and Suffix" | |
exit 1 | |
} | |
} | |
Set-Content $pidFile -Value $PID | |
$ErrorActionPreference = "Continue" | |
if ($AddDefaultRouteV6) { | |
$null = New-NetRoute "::/0" -InterfaceAlias $tunName -RouteMetric 1024 | |
} | |
while ($true) { | |
if ($DnsName) { | |
$record = Resolve-DnsName $DnsName -Type $DnsType | |
if ($record -and $record.Type -in ("A", "AAAA")) { | |
$addr = $record.IPAddress | |
if ($record.Type -eq "AAAA") { | |
$addr = "[$addr]" | |
} | |
if ($lastAddr -ne $addr) { | |
$argList = "set", $tunName, "peer", $Peer, "endpoint", "${addr}:$Port" | |
Start-Process "wg" -ArgumentList $argList | |
$lastAddr = $addr | |
} | |
} | |
} | |
if ($Suffix) { | |
if (!$DnsName -or $DnsNameV6 -ne $DnsName -or $record.Type -ne "AAAA") { | |
$record = Resolve-DnsName $DnsNameV6 -Type "AAAA" | |
} | |
$addrV6 = if ($record -and $record.Type -eq "AAAA") { | |
BigIntToIpv6Addr (((Ipv6AddrToBigInt $record.IPAddress) -band $prefixMask) -bor $suffixBits) | |
} | |
else { $null } | |
if ($lastAddrV6 -ne $addrV6) { | |
if ($null -ne $lastAddrV6) { | |
Remove-NetIPAddress $lastAddrV6 -InterfaceAlias $tunName -Confirm:$false | |
} | |
if ($null -ne $addrV6) { | |
$null = New-NetIPAddress $addrV6 -InterfaceAlias $tunName | |
} | |
} | |
$lastAddrV6 = $addrV6 | |
} | |
Start-Sleep 60 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
eth_if="eth0" | |
wg_if=$1 | |
trap cleanup SIGINT | |
trap cleanup SIGTERM | |
cleanup() { | |
prefix="" | |
update | |
exit | |
} | |
count_colons() { | |
local colons=${1//[^:]} | |
echo ${#colons} | |
} | |
concat_addr() { | |
prefix_colons=$(count_colons $1) | |
suffix_colons=$(count_colons $2) | |
colon_count=$((prefix_colons+suffix_colons)) | |
if [[ "$colon_count" == "8" ]]; then | |
echo ${1%:}$2 | |
else | |
echo $1$2 | |
fi | |
} | |
echo_eval() { | |
echo "[#] $1" | |
eval "$1" | |
} | |
update() { | |
if [[ "$prefix" == "$last_prefix" ]]; then | |
return | |
fi | |
sed_exp="" | |
suffixes=$(grep -Po '2001:db8::\K[0-9a-f:]*' "/etc/wireguard/$wg_if.conf") | |
while read -r suffix; do | |
if [[ -n "$last_prefix" ]]; then | |
last_addr=$(concat_addr $last_prefix $suffix) | |
echo_eval "ip -6 neigh del proxy $last_addr dev $eth_if" | |
echo_eval "ip -6 route del $last_addr dev $wg_if" | |
fi | |
if [[ -n "$prefix" ]]; then | |
addr=$(concat_addr $prefix $suffix) | |
echo_eval "ip -6 route add $addr dev $wg_if" | |
echo_eval "ip -6 neigh add proxy $addr dev $eth_if" | |
sed_exp="s/2001:db8::$suffix/$addr/g;$sed_exp" | |
fi | |
done <<< "$suffixes" | |
if [[ -z "$inited" ]]; then | |
echo_eval "sysctl net.ipv6.conf.all.forwarding=1" | |
inited=true | |
fi | |
echo_eval "wg syncconf $wg_if <(wg-quick strip $wg_if | sed -e '$sed_exp')" | |
last_prefix=$prefix | |
} | |
coproc (ip -6 route show dev $eth_if && ip -6 monitor route dev $eth_if) | |
while read -r -u ${COPROC[0]} route; do | |
if [[ "$route" =~ ^([0-9a-f:]*)/64\ proto\ ra ]]; then | |
prefix=${BASH_REMATCH[1]} | |
update | |
fi | |
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Unit] | |
Description=WireGuard NDP proxy for %I | |
[Service] | |
Type=simple | |
ExecStart=/usr/local/sbin/wg-ndproxy.sh %i |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment