mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-22 16:30:27 +00:00
Merge pull request #618 from yggdrasil-network/goodbyewater
Replace Water library with Wireguard's tun package (inc. Wintun support on Windows)
This commit is contained in:
commit
9967541627
@ -174,13 +174,6 @@ jobs:
|
|||||||
GOOS=freebsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-amd64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-freebsd-amd64;
|
GOOS=freebsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-amd64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-freebsd-amd64;
|
||||||
GOOS=freebsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-i386 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-freebsd-i386;
|
GOOS=freebsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-i386 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-freebsd-i386;
|
||||||
|
|
||||||
- run:
|
|
||||||
name: Build for NetBSD
|
|
||||||
command: |
|
|
||||||
rm -f {yggdrasil,yggdrasilctl}
|
|
||||||
GOOS=netbsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-netbsd-amd64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-netbsd-amd64;
|
|
||||||
GOOS=netbsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-netbsd-i386 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-netbsd-i386;
|
|
||||||
|
|
||||||
- run:
|
- run:
|
||||||
name: Build for Windows
|
name: Build for Windows
|
||||||
command: |
|
command: |
|
||||||
|
20
appveyor.yml
Normal file
20
appveyor.yml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
version: '{build}'
|
||||||
|
pull_requests:
|
||||||
|
do_not_increment_build_number: true
|
||||||
|
os: Visual Studio 2017
|
||||||
|
shallow_clone: false
|
||||||
|
|
||||||
|
environment:
|
||||||
|
MSYS2_PATH_TYPE: inherit
|
||||||
|
CHERE_INVOKING: enabled_from_arguments
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- cmd: >-
|
||||||
|
cd %APPVEYOR_BUILD_FOLDER%
|
||||||
|
- c:\msys64\usr\bin\bash -lc "./contrib/msi/build-msi.sh x64"
|
||||||
|
- c:\msys64\usr\bin\bash -lc "./contrib/msi/build-msi.sh x86"
|
||||||
|
|
||||||
|
test: off
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
- path: '*.msi'
|
205
contrib/msi/build-msi.sh
Normal file
205
contrib/msi/build-msi.sh
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# This script generates an MSI file for Yggdrasil for a given architecture. It
|
||||||
|
# needs to run on Windows within MSYS2 and Go 1.13 or later must be installed on
|
||||||
|
# the system and within the PATH. This is ran currently by Appveyor (see
|
||||||
|
# appveyor.yml in the repository root) for both x86 and x64.
|
||||||
|
#
|
||||||
|
# Author: Neil Alexander <neilalexander@users.noreply.github.com>
|
||||||
|
|
||||||
|
# Get arch from command line if given
|
||||||
|
PKGARCH=$1
|
||||||
|
if [ "${PKGARCH}" == "" ];
|
||||||
|
then
|
||||||
|
echo "tell me the architecture: x86 or x64"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the rest of the repository history. This is needed within Appveyor because
|
||||||
|
# otherwise we don't get all of the branch histories and therefore the semver
|
||||||
|
# scripts don't work properly.
|
||||||
|
if [ "${APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH}" != "" ];
|
||||||
|
then
|
||||||
|
git fetch --all
|
||||||
|
git checkout ${APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH}
|
||||||
|
elif [ "${APPVEYOR_REPO_BRANCH}" != "" ];
|
||||||
|
then
|
||||||
|
git fetch --all
|
||||||
|
git checkout ${APPVEYOR_REPO_BRANCH}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install prerequisites within MSYS2
|
||||||
|
pacman -S --needed --noconfirm unzip git curl
|
||||||
|
|
||||||
|
# Download the wix tools!
|
||||||
|
if [ ! -d wixbin ];
|
||||||
|
then
|
||||||
|
curl -LO https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip
|
||||||
|
if [ `md5sum wix311-binaries.zip | cut -f 1 -d " "` != "47a506f8ab6666ee3cc502fb07d0ee2a" ];
|
||||||
|
then
|
||||||
|
echo "wix package didn't match expected checksum"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
mkdir -p wixbin
|
||||||
|
unzip -o wix311-binaries.zip -d wixbin || (
|
||||||
|
echo "failed to unzip WiX"
|
||||||
|
exit 1
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build Yggdrasil!
|
||||||
|
[ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build
|
||||||
|
[ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build
|
||||||
|
|
||||||
|
# Create the postinstall script
|
||||||
|
cat > config.bat << EOF
|
||||||
|
if not exist yggdrasil.conf (
|
||||||
|
yggdrasil.exe -genconf > yggdrasil.conf
|
||||||
|
)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Work out metadata for the package info
|
||||||
|
PKGNAME=$(sh contrib/semver/name.sh)
|
||||||
|
PKGVERSION=$(sh contrib/semver/version.sh --bare)
|
||||||
|
PKGVERSIONMS=$(echo $PKGVERSION | tr - .)
|
||||||
|
[ "${PKGARCH}" == "x64" ] && \
|
||||||
|
PKGGUID="77757838-1a23-40a5-a720-c3b43e0260cc" PKGINSTFOLDER="ProgramFiles64Folder" || \
|
||||||
|
PKGGUID="54a3294e-a441-4322-aefb-3bb40dd022bb" PKGINSTFOLDER="ProgramFilesFolder"
|
||||||
|
|
||||||
|
# Download the Wintun driver
|
||||||
|
if [ $PKGARCH = "x64" ]; then
|
||||||
|
PKGMSMNAME=wintun-x64.msm
|
||||||
|
curl -o ${PKGMSMNAME} https://www.wintun.net/builds/wintun-amd64-0.7.msm || (echo "couldn't get wintun"; exit 1)
|
||||||
|
elif [ $PKGARCH = "x86" ]; then
|
||||||
|
PKGMSMNAME=wintun-x86.msm
|
||||||
|
curl -o ${PKGMSMNAME} https://www.wintun.net/builds/wintun-x86-0.7.msm || (echo "couldn't get wintun"; exit 1)
|
||||||
|
else
|
||||||
|
echo "wasn't sure which architecture to get wintun for"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate the wix.xml file
|
||||||
|
cat > wix.xml << EOF
|
||||||
|
<?xml version="1.0" encoding="windows-1252"?>
|
||||||
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||||
|
<Product
|
||||||
|
Name="Yggdrasil (${PKGNAME} branch)"
|
||||||
|
Id="*"
|
||||||
|
UpgradeCode="${PKGGUID}"
|
||||||
|
Language="1033"
|
||||||
|
Codepage="1252"
|
||||||
|
Version="${PKGVERSIONMS}"
|
||||||
|
Manufacturer="github.com/yggdrasil-network">
|
||||||
|
|
||||||
|
<Package
|
||||||
|
Id="*"
|
||||||
|
Keywords="Installer"
|
||||||
|
Description="Yggdrasil Network Installer"
|
||||||
|
Comments="This is the Yggdrasil Network binary."
|
||||||
|
Manufacturer="github.com/yggdrasil-network"
|
||||||
|
InstallerVersion="200"
|
||||||
|
Languages="1033"
|
||||||
|
Compressed="yes"
|
||||||
|
Platform="${PKGARCH}"
|
||||||
|
SummaryCodepage="1252" />
|
||||||
|
|
||||||
|
<MajorUpgrade
|
||||||
|
AllowDowngrades="yes" />
|
||||||
|
|
||||||
|
<Media
|
||||||
|
Id="1"
|
||||||
|
Cabinet="Media.cab"
|
||||||
|
EmbedCab="yes" />
|
||||||
|
|
||||||
|
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||||
|
<Directory Id="${PKGINSTFOLDER}" Name="PFiles">
|
||||||
|
<Directory Id="YggdrasilInstallFolder" Name="Yggdrasil">
|
||||||
|
|
||||||
|
<Component Id="MainExecutable" Guid="c2119231-2aa3-4962-867a-9759c87beb24">
|
||||||
|
<File
|
||||||
|
Id="Yggdrasil"
|
||||||
|
Name="yggdrasil.exe"
|
||||||
|
DiskId="1"
|
||||||
|
Source="yggdrasil.exe"
|
||||||
|
KeyPath="yes" />
|
||||||
|
|
||||||
|
<ServiceInstall
|
||||||
|
Id="ServiceInstaller"
|
||||||
|
Account="LocalSystem"
|
||||||
|
Description="Yggdrasil Network router process"
|
||||||
|
DisplayName="Yggdrasil Service"
|
||||||
|
ErrorControl="normal"
|
||||||
|
LoadOrderGroup="NetworkProvider"
|
||||||
|
Name="yggdrasil"
|
||||||
|
Start="auto"
|
||||||
|
Type="ownProcess"
|
||||||
|
Arguments='-useconffile "[YggdrasilInstallFolder]yggdrasil.conf" -logto "[YggdrasilInstallFolder]yggdrasil.log"'
|
||||||
|
Vital="yes" />
|
||||||
|
|
||||||
|
<ServiceControl
|
||||||
|
Id="ServiceControl"
|
||||||
|
Name="yggdrasil"
|
||||||
|
Start="install"
|
||||||
|
Stop="both"
|
||||||
|
Remove="uninstall" />
|
||||||
|
</Component>
|
||||||
|
|
||||||
|
<Component Id="CtrlExecutable" Guid="a916b730-974d-42a1-b687-d9d504cbb86a">
|
||||||
|
<File
|
||||||
|
Id="Yggdrasilctl"
|
||||||
|
Name="yggdrasilctl.exe"
|
||||||
|
DiskId="1"
|
||||||
|
Source="yggdrasilctl.exe"
|
||||||
|
KeyPath="yes"/>
|
||||||
|
</Component>
|
||||||
|
|
||||||
|
<Component Id="ConfigScript" Guid="64a3733b-c98a-4732-85f3-20cd7da1a785">
|
||||||
|
<File
|
||||||
|
Id="Configbat"
|
||||||
|
Name="updateconfig.bat"
|
||||||
|
DiskId="1"
|
||||||
|
Source="config.bat"
|
||||||
|
KeyPath="yes"/>
|
||||||
|
</Component>
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Merge
|
||||||
|
Id="Wintun"
|
||||||
|
Language="0"
|
||||||
|
DiskId="1"
|
||||||
|
SourceFile="${PKGMSMNAME}" />
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Feature Id="Complete" Level="1">
|
||||||
|
<MergeRef Id="Wintun" />
|
||||||
|
<ComponentRef Id="MainExecutable" />
|
||||||
|
<ComponentRef Id="CtrlExecutable" />
|
||||||
|
<ComponentRef Id="ConfigScript" />
|
||||||
|
</Feature>
|
||||||
|
|
||||||
|
<CustomAction
|
||||||
|
Id="UpdateGenerateConfig"
|
||||||
|
Directory="YggdrasilInstallFolder"
|
||||||
|
ExeCommand="cmd.exe /c updateconfig.bat"
|
||||||
|
Execute="deferred"
|
||||||
|
Impersonate="no"
|
||||||
|
Return="check" />
|
||||||
|
|
||||||
|
<InstallExecuteSequence>
|
||||||
|
<Custom
|
||||||
|
Action="UpdateGenerateConfig"
|
||||||
|
Before="InstallServices">
|
||||||
|
NOT Installed AND NOT REMOVE
|
||||||
|
</Custom>
|
||||||
|
</InstallExecuteSequence>
|
||||||
|
|
||||||
|
</Product>
|
||||||
|
</Wix>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Generate the MSI
|
||||||
|
CANDLEFLAGS="-nologo"
|
||||||
|
LIGHTFLAGS="-nologo -spdb -sice:ICE71 -sice:ICE61"
|
||||||
|
wixbin/candle $CANDLEFLAGS -out ${PKGNAME}-${PKGVERSION}-${PKGARCH}.wixobj -arch ${PKGARCH} wix.xml && \
|
||||||
|
wixbin/light $LIGHTFLAGS -out ${PKGNAME}-${PKGVERSION}-${PKGARCH}.msi ${PKGNAME}-${PKGVERSION}-${PKGARCH}.wixobj
|
11
go.mod
11
go.mod
@ -9,13 +9,12 @@ require (
|
|||||||
github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible
|
github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible
|
||||||
github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0
|
github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0
|
||||||
github.com/mitchellh/mapstructure v1.1.2
|
github.com/mitchellh/mapstructure v1.1.2
|
||||||
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091
|
|
||||||
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b // indirect
|
|
||||||
github.com/vishvananda/netlink v1.0.0
|
github.com/vishvananda/netlink v1.0.0
|
||||||
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f // indirect
|
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f // indirect
|
||||||
github.com/yggdrasil-network/water v0.0.0-20190812103929-c83fe40250f8
|
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
|
golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914
|
||||||
golang.org/x/net v0.0.0-20191021144547-ec77196f6094
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e
|
||||||
golang.org/x/sys v0.0.0-20191024172528-b4ff53e7a1cb
|
|
||||||
golang.org/x/text v0.3.2
|
golang.org/x/text v0.3.2
|
||||||
|
golang.zx2c4.com/wireguard v0.0.20191013-0.20191030132932-4cdf805b29b1
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.0.35-0.20191123133119-cb4a03094c25
|
||||||
)
|
)
|
||||||
|
32
go.sum
32
go.sum
@ -8,29 +8,37 @@ github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible h1:b
|
|||||||
github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio=
|
github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio=
|
||||||
github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0 h1:YnZmFjg0Nvk8851WTVWlqMC1ecJH07Ctz+Ezxx4u54g=
|
github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0 h1:YnZmFjg0Nvk8851WTVWlqMC1ecJH07Ctz+Ezxx4u54g=
|
||||||
github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0/go.mod h1:rUi0/YffDo1oXBOGn1KRq7Fr07LX48XEBecQnmwjsAo=
|
github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0/go.mod h1:rUi0/YffDo1oXBOGn1KRq7Fr07LX48XEBecQnmwjsAo=
|
||||||
|
github.com/lxn/walk v0.0.0-20191031081659-c0bb82ae46cb/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
|
||||||
|
github.com/lxn/win v0.0.0-20191024121223-cc00c7492fe1 h1:h0wbuSK8xUNmMwDdCxZx2OLdkVck6Bb31zj4CxCN5I4=
|
||||||
|
github.com/lxn/win v0.0.0-20191024121223-cc00c7492fe1/go.mod h1:ouWl4wViUNh8tPSIwxTVMuS014WakR1hqvBc2I0bMoA=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 h1:1zN6ImoqhSJhN8hGXFaJlSC8msLmIbX8bFqOfWLKw0w=
|
|
||||||
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091/go.mod h1:N20Z5Y8oye9a7HmytmZ+tr8Q2vlP0tAHP13kTHzwvQY=
|
|
||||||
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b h1:+y4hCMc/WKsDbAPsOQZgBSaSZ26uh2afyaWeVg/3s/c=
|
|
||||||
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
|
||||||
github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM=
|
github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM=
|
||||||
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||||
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f h1:nBX3nTcmxEtHSERBJaIo1Qa26VwRaopnZmfDQUXsF4I=
|
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f h1:nBX3nTcmxEtHSERBJaIo1Qa26VwRaopnZmfDQUXsF4I=
|
||||||
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
|
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
|
||||||
github.com/yggdrasil-network/water v0.0.0-20190812103929-c83fe40250f8 h1:YY9Pg2BEp0jeUVU60svTOaDr+fs1ySC9RbdC1Qc6wOw=
|
|
||||||
github.com/yggdrasil-network/water v0.0.0-20190812103929-c83fe40250f8/go.mod h1:R0SBCsugm+Sf1katgTb2t7GXMm+nRIv43tM4VDZbaOs=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4=
|
||||||
|
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20191021144547-ec77196f6094 h1:5O4U9trLjNpuhpynaDsqwCk+Tw6seqJz1EbqbnzHrc8=
|
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914 h1:MlY3mEfbnWGmUi4rtHOtNnnnN4UJRGSyLPx+DXA5Sq4=
|
||||||
|
golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191024172528-b4ff53e7a1cb h1:ZxSglHghKPYD8WDeRUzRJrUJtDF0PxsTUSxyqr9/5BI=
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191024172528-b4ff53e7a1cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA=
|
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.zx2c4.com/wireguard v0.0.20191013-0.20191030132932-4cdf805b29b1 h1:KxtBKNgJUQG8vwZzJKkwBGOcqp95xLu6A6KIMde1kl0=
|
||||||
|
golang.zx2c4.com/wireguard v0.0.20191013-0.20191030132932-4cdf805b29b1/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4=
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.0.35-0.20191123133119-cb4a03094c25 h1:TreP+furSwdqoSToFrwb1S5cwxb7jhOsnwj2MsDeT+4=
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.0.35-0.20191123133119-cb4a03094c25/go.mod h1:EO8KCpT944a9CnwHJLZ1sl84FfIrY42fP/fcXUuYhKM=
|
||||||
|
@ -5,7 +5,7 @@ Yggdrasil node.
|
|||||||
The configuration contains, amongst other things, encryption keys which are used
|
The configuration contains, amongst other things, encryption keys which are used
|
||||||
to derive a node's identity, information about peerings and node information
|
to derive a node's identity, information about peerings and node information
|
||||||
that is shared with the network. There are also some module-specific options
|
that is shared with the network. There are also some module-specific options
|
||||||
related to TUN/TAP, multicast and the admin socket.
|
related to TUN, multicast and the admin socket.
|
||||||
|
|
||||||
In order for a node to maintain the same identity across restarts, you should
|
In order for a node to maintain the same identity across restarts, you should
|
||||||
persist the configuration onto the filesystem or into some configuration storage
|
persist the configuration onto the filesystem or into some configuration storage
|
||||||
@ -70,9 +70,8 @@ type NodeConfig struct {
|
|||||||
SigningPublicKey string `comment:"Your public signing key. You should not ordinarily need to share\nthis with anyone."`
|
SigningPublicKey string `comment:"Your public signing key. You should not ordinarily need to share\nthis with anyone."`
|
||||||
SigningPrivateKey string `comment:"Your private signing key. DO NOT share this with anyone!"`
|
SigningPrivateKey string `comment:"Your private signing key. DO NOT share this with anyone!"`
|
||||||
LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."`
|
LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."`
|
||||||
IfName string `comment:"Local network interface name for TUN/TAP adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN/TAP."`
|
IfName string `comment:"Local network interface name for TUN adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN."`
|
||||||
IfTAPMode bool `comment:"Set local network interface to TAP mode rather than TUN mode if\nsupported by your platform - option will be ignored if not."`
|
IfMTU int `comment:"Maximux Transmission Unit (MTU) size for your local TUN interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."`
|
||||||
IfMTU int `comment:"Maximux Transmission Unit (MTU) size for your local TUN/TAP interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."`
|
|
||||||
SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."`
|
SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."`
|
||||||
TunnelRouting TunnelRouting `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil. This effectively\nallows you to use Yggdrasil to route to, or to bridge other networks,\nsimilar to a VPN tunnel. Tunnelling works between any two nodes and\ndoes not require them to be directly peered."`
|
TunnelRouting TunnelRouting `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil. This effectively\nallows you to use Yggdrasil to route to, or to bridge other networks,\nsimilar to a VPN tunnel. Tunnelling works between any two nodes and\ndoes not require them to be directly peered."`
|
||||||
SwitchOptions SwitchOptions `comment:"Advanced options for tuning the switch. Normally you will not need\nto edit these options."`
|
SwitchOptions SwitchOptions `comment:"Advanced options for tuning the switch. Normally you will not need\nto edit these options."`
|
||||||
@ -127,7 +126,6 @@ func GenerateConfig() *NodeConfig {
|
|||||||
cfg.MulticastInterfaces = defaults.GetDefaults().DefaultMulticastInterfaces
|
cfg.MulticastInterfaces = defaults.GetDefaults().DefaultMulticastInterfaces
|
||||||
cfg.IfName = defaults.GetDefaults().DefaultIfName
|
cfg.IfName = defaults.GetDefaults().DefaultIfName
|
||||||
cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU
|
cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU
|
||||||
cfg.IfTAPMode = defaults.GetDefaults().DefaultIfTAPMode
|
|
||||||
cfg.SessionFirewall.Enable = false
|
cfg.SessionFirewall.Enable = false
|
||||||
cfg.SessionFirewall.AllowFromDirect = true
|
cfg.SessionFirewall.AllowFromDirect = true
|
||||||
cfg.SessionFirewall.AllowFromRemote = true
|
cfg.SessionFirewall.AllowFromRemote = true
|
||||||
|
@ -17,5 +17,4 @@ type platformDefaultParameters struct {
|
|||||||
MaximumIfMTU int
|
MaximumIfMTU int
|
||||||
DefaultIfMTU int
|
DefaultIfMTU int
|
||||||
DefaultIfName string
|
DefaultIfName string
|
||||||
DefaultIfTAPMode bool
|
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,5 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
DefaultIfMTU: 65535,
|
DefaultIfMTU: 65535,
|
||||||
DefaultIfName: "auto",
|
DefaultIfName: "auto",
|
||||||
DefaultIfTAPMode: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 32767,
|
MaximumIfMTU: 32767,
|
||||||
DefaultIfMTU: 32767,
|
DefaultIfMTU: 32767,
|
||||||
DefaultIfName: "/dev/tap0",
|
DefaultIfName: "/dev/tun0",
|
||||||
DefaultIfTAPMode: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,5 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
DefaultIfMTU: 65535,
|
DefaultIfMTU: 65535,
|
||||||
DefaultIfName: "auto",
|
DefaultIfName: "auto",
|
||||||
DefaultIfTAPMode: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
// +build netbsd
|
|
||||||
|
|
||||||
package defaults
|
|
||||||
|
|
||||||
// Sane defaults for the BSD platforms. The "default" options may be
|
|
||||||
// may be replaced by the running configuration.
|
|
||||||
func GetDefaults() platformDefaultParameters {
|
|
||||||
return platformDefaultParameters{
|
|
||||||
// Admin
|
|
||||||
DefaultAdminListen: "unix:///var/run/yggdrasil.sock",
|
|
||||||
|
|
||||||
// Configuration (used for yggdrasilctl)
|
|
||||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
|
||||||
|
|
||||||
// Multicast interfaces
|
|
||||||
DefaultMulticastInterfaces: []string{
|
|
||||||
".*",
|
|
||||||
},
|
|
||||||
|
|
||||||
// TUN/TAP
|
|
||||||
MaximumIfMTU: 9000,
|
|
||||||
DefaultIfMTU: 9000,
|
|
||||||
DefaultIfName: "/dev/tap0",
|
|
||||||
DefaultIfTAPMode: true,
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,7 +20,6 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 16384,
|
MaximumIfMTU: 16384,
|
||||||
DefaultIfMTU: 16384,
|
DefaultIfMTU: 16384,
|
||||||
DefaultIfName: "/dev/tap0",
|
DefaultIfName: "/dev/tun0",
|
||||||
DefaultIfTAPMode: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd
|
// +build !linux,!darwin,!windows,!openbsd,!freebsd
|
||||||
|
|
||||||
package defaults
|
package defaults
|
||||||
|
|
||||||
@ -21,6 +21,5 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
DefaultIfMTU: 65535,
|
DefaultIfMTU: 65535,
|
||||||
DefaultIfName: "none",
|
DefaultIfName: "none",
|
||||||
DefaultIfTAPMode: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
DefaultIfMTU: 65535,
|
DefaultIfMTU: 65535,
|
||||||
DefaultIfName: "auto",
|
DefaultIfName: "Yggdrasil",
|
||||||
DefaultIfTAPMode: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,7 @@ func (t *TunAdapter) SetupAdminHandlers(a *admin.AdminSocket) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
return admin.Info{
|
return admin.Info{
|
||||||
t.iface.Name(): admin.Info{
|
t.Name(): admin.Info{
|
||||||
"tap_mode": t.iface.IsTAP(),
|
|
||||||
"mtu": t.mtu,
|
"mtu": t.mtu,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -11,32 +11,16 @@ package tuntap
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/net/icmp"
|
"golang.org/x/net/icmp"
|
||||||
"golang.org/x/net/ipv6"
|
"golang.org/x/net/ipv6"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const len_ETHER = 14
|
const len_ETHER = 14
|
||||||
|
|
||||||
type ICMPv6 struct {
|
type ICMPv6 struct {
|
||||||
tun *TunAdapter
|
tun *TunAdapter
|
||||||
mylladdr net.IP
|
|
||||||
mymac net.HardwareAddr
|
|
||||||
peermacs map[address.Address]neighbor
|
|
||||||
peermacsmutex sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
type neighbor struct {
|
|
||||||
mac net.HardwareAddr
|
|
||||||
learned bool
|
|
||||||
lastadvertisement time.Time
|
|
||||||
lastsolicitation time.Time
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marshal returns the binary encoding of h.
|
// Marshal returns the binary encoding of h.
|
||||||
@ -61,182 +45,6 @@ func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) {
|
|||||||
// addresses.
|
// addresses.
|
||||||
func (i *ICMPv6) Init(t *TunAdapter) {
|
func (i *ICMPv6) Init(t *TunAdapter) {
|
||||||
i.tun = t
|
i.tun = t
|
||||||
i.peermacsmutex.Lock()
|
|
||||||
i.peermacs = make(map[address.Address]neighbor)
|
|
||||||
i.peermacsmutex.Unlock()
|
|
||||||
|
|
||||||
// Our MAC address and link-local address
|
|
||||||
i.mymac = net.HardwareAddr{
|
|
||||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x02}
|
|
||||||
i.mylladdr = net.IP{
|
|
||||||
0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFE}
|
|
||||||
copy(i.mymac[:], i.tun.addr[:])
|
|
||||||
copy(i.mylladdr[9:], i.tun.addr[1:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses an incoming ICMPv6 packet. The packet provided may be either an
|
|
||||||
// ethernet frame containing an IP packet, or the IP packet alone. This is
|
|
||||||
// determined by whether the TUN/TAP adapter is running in TUN (layer 3) or
|
|
||||||
// TAP (layer 2) mode. Returns an error condition which is nil if the ICMPv6
|
|
||||||
// module handled the packet or contains the error if not.
|
|
||||||
func (i *ICMPv6) ParsePacket(datain []byte) error {
|
|
||||||
var response []byte
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Parse the frame/packet
|
|
||||||
if i.tun.IsTAP() {
|
|
||||||
response, err = i.UnmarshalPacketL2(datain)
|
|
||||||
} else {
|
|
||||||
response, err = i.UnmarshalPacket(datain, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the packet to TUN/TAP
|
|
||||||
i.tun.iface.Write(response)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwraps the ethernet headers of an incoming ICMPv6 packet and hands off
|
|
||||||
// the IP packet to the ParsePacket function for further processing.
|
|
||||||
// A response buffer is also created for the response message, also complete
|
|
||||||
// with ethernet headers.
|
|
||||||
func (i *ICMPv6) UnmarshalPacketL2(datain []byte) ([]byte, error) {
|
|
||||||
// Ignore non-IPv6 frames
|
|
||||||
if binary.BigEndian.Uint16(datain[12:14]) != uint16(0x86DD) {
|
|
||||||
return nil, errors.New("Ignoring non-IPv6 frame")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hand over to ParsePacket to interpret the IPv6 packet
|
|
||||||
mac := datain[6:12]
|
|
||||||
ipv6packet, err := i.UnmarshalPacket(datain[len_ETHER:], &mac)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the response buffer
|
|
||||||
dataout := make([]byte, len_ETHER+ipv6.HeaderLen+32)
|
|
||||||
|
|
||||||
// Populate the response ethernet headers
|
|
||||||
copy(dataout[:6], datain[6:12])
|
|
||||||
copy(dataout[6:12], i.mymac[:])
|
|
||||||
binary.BigEndian.PutUint16(dataout[12:14], uint16(0x86DD))
|
|
||||||
|
|
||||||
// Copy the returned packet to our response ethernet frame
|
|
||||||
copy(dataout[len_ETHER:], ipv6packet)
|
|
||||||
return dataout, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwraps the IP headers of an incoming IPv6 packet and performs various
|
|
||||||
// sanity checks on the packet - i.e. is the packet an ICMPv6 packet, does the
|
|
||||||
// ICMPv6 message match a known expected type. The relevant handler function
|
|
||||||
// is then called and a response packet may be returned.
|
|
||||||
func (i *ICMPv6) UnmarshalPacket(datain []byte, datamac *[]byte) ([]byte, error) {
|
|
||||||
// Parse the IPv6 packet headers
|
|
||||||
ipv6Header, err := ipv6.ParseHeader(datain[:ipv6.HeaderLen])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the packet is IPv6
|
|
||||||
if ipv6Header.Version != ipv6.Version {
|
|
||||||
return nil, errors.New("Ignoring non-IPv6 packet")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the packet is ICMPv6
|
|
||||||
if ipv6Header.NextHeader != 58 {
|
|
||||||
return nil, errors.New("Ignoring non-ICMPv6 packet")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the ICMPv6 message contents
|
|
||||||
icmpv6Header, err := icmp.ParseMessage(58, datain[ipv6.HeaderLen:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for a supported message type
|
|
||||||
switch icmpv6Header.Type {
|
|
||||||
case ipv6.ICMPTypeNeighborSolicitation:
|
|
||||||
if !i.tun.IsTAP() {
|
|
||||||
return nil, errors.New("Ignoring Neighbor Solicitation in TUN mode")
|
|
||||||
}
|
|
||||||
response, err := i.HandleNDP(datain[ipv6.HeaderLen:])
|
|
||||||
if err == nil {
|
|
||||||
// Create our ICMPv6 response
|
|
||||||
responsePacket, err := CreateICMPv6(
|
|
||||||
ipv6Header.Src, i.mylladdr,
|
|
||||||
ipv6.ICMPTypeNeighborAdvertisement, 0,
|
|
||||||
&icmp.DefaultMessageBody{Data: response})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Send it back
|
|
||||||
return responsePacket, nil
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case ipv6.ICMPTypeNeighborAdvertisement:
|
|
||||||
if !i.tun.IsTAP() {
|
|
||||||
return nil, errors.New("Ignoring Neighbor Advertisement in TUN mode")
|
|
||||||
}
|
|
||||||
if datamac != nil {
|
|
||||||
var addr address.Address
|
|
||||||
var target address.Address
|
|
||||||
mac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
copy(addr[:], ipv6Header.Src[:])
|
|
||||||
copy(target[:], datain[48:64])
|
|
||||||
copy(mac[:], (*datamac)[:])
|
|
||||||
i.peermacsmutex.Lock()
|
|
||||||
neighbor := i.peermacs[target]
|
|
||||||
neighbor.mac = mac
|
|
||||||
neighbor.learned = true
|
|
||||||
neighbor.lastadvertisement = time.Now()
|
|
||||||
i.peermacs[target] = neighbor
|
|
||||||
i.peermacsmutex.Unlock()
|
|
||||||
i.tun.log.Debugln("Learned peer MAC", mac.String(), "for", net.IP(target[:]).String())
|
|
||||||
/*
|
|
||||||
i.tun.log.Debugln("Peer MAC table:")
|
|
||||||
i.peermacsmutex.RLock()
|
|
||||||
for t, n := range i.peermacs {
|
|
||||||
if n.learned {
|
|
||||||
i.tun.log.Debugln("- Target", net.IP(t[:]).String(), "has MAC", n.mac.String())
|
|
||||||
} else {
|
|
||||||
i.tun.log.Debugln("- Target", net.IP(t[:]).String(), "is not learned yet")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i.peermacsmutex.RUnlock()
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
return nil, errors.New("No response needed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("ICMPv6 type not matched")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
|
|
||||||
// parameters, complete with ethernet and IP headers, which can be written
|
|
||||||
// directly to a TAP adapter.
|
|
||||||
func (i *ICMPv6) CreateICMPv6L2(dstmac net.HardwareAddr, dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
|
|
||||||
// Pass through to CreateICMPv6
|
|
||||||
ipv6packet, err := CreateICMPv6(dst, src, mtype, mcode, mbody)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the response buffer
|
|
||||||
dataout := make([]byte, len_ETHER+len(ipv6packet))
|
|
||||||
|
|
||||||
// Populate the response ethernet headers
|
|
||||||
copy(dataout[:6], dstmac[:6])
|
|
||||||
copy(dataout[6:12], i.mymac[:])
|
|
||||||
binary.BigEndian.PutUint16(dataout[12:14], uint16(0x86DD))
|
|
||||||
|
|
||||||
// Copy the returned packet to our response ethernet frame
|
|
||||||
copy(dataout[len_ETHER:], ipv6packet)
|
|
||||||
return dataout, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
|
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
|
||||||
@ -281,106 +89,3 @@ func CreateICMPv6(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody
|
|||||||
// Send it back
|
// Send it back
|
||||||
return responsePacket, nil
|
return responsePacket, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ICMPv6) Solicit(addr address.Address) {
|
|
||||||
retries := 5
|
|
||||||
for retries > 0 {
|
|
||||||
retries--
|
|
||||||
i.peermacsmutex.RLock()
|
|
||||||
if n, ok := i.peermacs[addr]; ok && n.learned {
|
|
||||||
i.tun.log.Debugln("MAC learned for", net.IP(addr[:]).String())
|
|
||||||
i.peermacsmutex.RUnlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
i.peermacsmutex.RUnlock()
|
|
||||||
i.tun.log.Debugln("Sending neighbor solicitation for", net.IP(addr[:]).String())
|
|
||||||
i.peermacsmutex.Lock()
|
|
||||||
if n, ok := i.peermacs[addr]; !ok {
|
|
||||||
i.peermacs[addr] = neighbor{
|
|
||||||
lastsolicitation: time.Now(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
n.lastsolicitation = time.Now()
|
|
||||||
}
|
|
||||||
i.peermacsmutex.Unlock()
|
|
||||||
request, err := i.createNDPL2(addr)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if _, err := i.tun.iface.Write(request); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
i.tun.log.Debugln("Sent neighbor solicitation for", net.IP(addr[:]).String())
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ICMPv6) getNeighbor(addr address.Address) (neighbor, bool) {
|
|
||||||
i.peermacsmutex.RLock()
|
|
||||||
defer i.peermacsmutex.RUnlock()
|
|
||||||
|
|
||||||
n, ok := i.peermacs[addr]
|
|
||||||
return n, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ICMPv6) createNDPL2(dst address.Address) ([]byte, error) {
|
|
||||||
// Create the ND payload
|
|
||||||
var payload [28]byte
|
|
||||||
copy(payload[:4], []byte{0x00, 0x00, 0x00, 0x00}) // Flags
|
|
||||||
copy(payload[4:20], dst[:]) // Destination
|
|
||||||
copy(payload[20:22], []byte{0x01, 0x01}) // Type & length
|
|
||||||
copy(payload[22:28], i.mymac[:6]) // Link layer address
|
|
||||||
|
|
||||||
// Create the ICMPv6 solicited-node address
|
|
||||||
var dstaddr address.Address
|
|
||||||
copy(dstaddr[:13], []byte{
|
|
||||||
0xFF, 0x02, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0xFF})
|
|
||||||
copy(dstaddr[13:], dst[13:16])
|
|
||||||
|
|
||||||
// Create the multicast MAC
|
|
||||||
dstmac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
copy(dstmac[:2], []byte{0x33, 0x33})
|
|
||||||
copy(dstmac[2:6], dstaddr[12:16])
|
|
||||||
|
|
||||||
// Create the ND request
|
|
||||||
requestPacket, err := i.CreateICMPv6L2(
|
|
||||||
dstmac, dstaddr[:], i.mylladdr,
|
|
||||||
ipv6.ICMPTypeNeighborSolicitation, 0,
|
|
||||||
&icmp.DefaultMessageBody{Data: payload[:]})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestPacket, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a response to an NDP discovery packet. This is effectively called
|
|
||||||
// when the host operating system generates an NDP request for any address in
|
|
||||||
// the fd00::/8 range, so that the operating system knows to route that traffic
|
|
||||||
// to the Yggdrasil TAP adapter.
|
|
||||||
func (i *ICMPv6) HandleNDP(in []byte) ([]byte, error) {
|
|
||||||
// Ignore NDP requests for anything outside of fd00::/8
|
|
||||||
var source address.Address
|
|
||||||
copy(source[:], in[8:])
|
|
||||||
var snet address.Subnet
|
|
||||||
copy(snet[:], in[8:])
|
|
||||||
switch {
|
|
||||||
case source.IsValid():
|
|
||||||
case snet.IsValid():
|
|
||||||
default:
|
|
||||||
return nil, errors.New("Not an NDP for 0200::/7")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create our NDP message body response
|
|
||||||
body := make([]byte, 28)
|
|
||||||
binary.BigEndian.PutUint32(body[:4], uint32(0x40000000)) // Flags
|
|
||||||
copy(body[4:20], in[8:24]) // Target address
|
|
||||||
body[20] = uint8(2) // Type: Target link-layer address
|
|
||||||
body[21] = uint8(1) // Length: 1x address (8 bytes)
|
|
||||||
copy(body[22:28], i.mymac[:6])
|
|
||||||
|
|
||||||
// Send it back
|
|
||||||
return body, nil
|
|
||||||
}
|
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
package tuntap
|
package tuntap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/songgao/packets/ethernet"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
@ -14,6 +9,8 @@ import (
|
|||||||
"github.com/Arceliar/phony"
|
"github.com/Arceliar/phony"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const TUN_OFFSET_BYTES = 4
|
||||||
|
|
||||||
type tunWriter struct {
|
type tunWriter struct {
|
||||||
phony.Inbox
|
phony.Inbox
|
||||||
tun *TunAdapter
|
tun *TunAdapter
|
||||||
@ -25,80 +22,29 @@ func (w *tunWriter) writeFrom(from phony.Actor, b []byte) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// write is pretty loose with the memory safety rules, e.g. it assumes it can read w.tun.iface.IsTap() safely
|
// write is pretty loose with the memory safety rules, e.g. it assumes it can
|
||||||
|
// read w.tun.iface.IsTap() safely
|
||||||
func (w *tunWriter) _write(b []byte) {
|
func (w *tunWriter) _write(b []byte) {
|
||||||
|
defer util.PutBytes(b)
|
||||||
var written int
|
var written int
|
||||||
var err error
|
var err error
|
||||||
n := len(b)
|
n := len(b)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if w.tun.iface.IsTAP() {
|
temp := append(util.ResizeBytes(util.GetBytes(), TUN_OFFSET_BYTES), b...)
|
||||||
sendndp := func(dstAddr address.Address) {
|
defer util.PutBytes(temp)
|
||||||
neigh, known := w.tun.icmpv6.getNeighbor(dstAddr)
|
written, err = w.tun.iface.Write(temp, TUN_OFFSET_BYTES)
|
||||||
known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30)
|
|
||||||
if !known {
|
|
||||||
w.tun.icmpv6.Solicit(dstAddr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
peermac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
var dstAddr address.Address
|
|
||||||
var peerknown bool
|
|
||||||
if b[0]&0xf0 == 0x40 {
|
|
||||||
dstAddr = w.tun.addr
|
|
||||||
} else if b[0]&0xf0 == 0x60 {
|
|
||||||
if !bytes.Equal(w.tun.addr[:16], dstAddr[:16]) && !bytes.Equal(w.tun.subnet[:8], dstAddr[:8]) {
|
|
||||||
dstAddr = w.tun.addr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if neighbor, ok := w.tun.icmpv6.getNeighbor(dstAddr); ok && neighbor.learned {
|
|
||||||
// If we've learned the MAC of a 300::/7 address, for example, or a CKR
|
|
||||||
// address, use the MAC address of that
|
|
||||||
peermac = neighbor.mac
|
|
||||||
peerknown = true
|
|
||||||
} else if neighbor, ok := w.tun.icmpv6.getNeighbor(w.tun.addr); ok && neighbor.learned {
|
|
||||||
// Otherwise send directly to the MAC address of the host if that's
|
|
||||||
// known instead
|
|
||||||
peermac = neighbor.mac
|
|
||||||
peerknown = true
|
|
||||||
} else {
|
|
||||||
// Nothing has been discovered, try to discover the destination
|
|
||||||
sendndp(w.tun.addr)
|
|
||||||
}
|
|
||||||
if peerknown {
|
|
||||||
var proto ethernet.Ethertype
|
|
||||||
switch {
|
|
||||||
case b[0]&0xf0 == 0x60:
|
|
||||||
proto = ethernet.IPv6
|
|
||||||
case b[0]&0xf0 == 0x40:
|
|
||||||
proto = ethernet.IPv4
|
|
||||||
}
|
|
||||||
var frame ethernet.Frame
|
|
||||||
frame.Prepare(
|
|
||||||
peermac[:6], // Destination MAC address
|
|
||||||
w.tun.icmpv6.mymac[:6], // Source MAC address
|
|
||||||
ethernet.NotTagged, // VLAN tagging
|
|
||||||
proto, // Ethertype
|
|
||||||
len(b)) // Payload length
|
|
||||||
copy(frame[tun_ETHER_HEADER_LENGTH:], b[:n])
|
|
||||||
n += tun_ETHER_HEADER_LENGTH
|
|
||||||
written, err = w.tun.iface.Write(frame[:n])
|
|
||||||
} else {
|
|
||||||
w.tun.log.Errorln("TUN/TAP iface write error: no peer MAC known for", net.IP(dstAddr[:]).String(), "- dropping packet")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
written, err = w.tun.iface.Write(b[:n])
|
|
||||||
util.PutBytes(b)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.tun.Act(w, func() {
|
w.tun.Act(w, func() {
|
||||||
if !w.tun.isOpen {
|
if !w.tun.isOpen {
|
||||||
w.tun.log.Errorln("TUN/TAP iface write error:", err)
|
w.tun.log.Errorln("TUN iface write error:", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if written != n {
|
if written != n+TUN_OFFSET_BYTES {
|
||||||
w.tun.log.Errorln("TUN/TAP iface write mismatch:", written, "bytes written vs", n, "bytes given")
|
// FIXME some platforms return the wrong number of bytes written, causing error spam
|
||||||
|
//w.tun.log.Errorln("TUN iface write mismatch:", written, "bytes written vs", n+TUN_OFFSET_BYTES, "bytes given")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,13 +55,18 @@ type tunReader struct {
|
|||||||
|
|
||||||
func (r *tunReader) _read() {
|
func (r *tunReader) _read() {
|
||||||
// Get a slice to store the packet in
|
// Get a slice to store the packet in
|
||||||
recvd := util.ResizeBytes(util.GetBytes(), 65535+tun_ETHER_HEADER_LENGTH)
|
recvd := util.ResizeBytes(util.GetBytes(), r.tun.mtu+TUN_OFFSET_BYTES)
|
||||||
// Wait for a packet to be delivered to us through the TUN/TAP adapter
|
// Wait for a packet to be delivered to us through the TUN adapter
|
||||||
n, err := r.tun.iface.Read(recvd)
|
n, err := r.tun.iface.Read(recvd, TUN_OFFSET_BYTES)
|
||||||
if n <= 0 {
|
if n <= TUN_OFFSET_BYTES || err != nil {
|
||||||
|
r.tun.log.Errorln("Error reading TUN:", err)
|
||||||
|
ferr := r.tun.iface.Flush()
|
||||||
|
if ferr != nil {
|
||||||
|
r.tun.log.Errorln("Unable to flush packets:", ferr)
|
||||||
|
}
|
||||||
util.PutBytes(recvd)
|
util.PutBytes(recvd)
|
||||||
} else {
|
} else {
|
||||||
r.tun.handlePacketFrom(r, recvd[:n], err)
|
r.tun.handlePacketFrom(r, recvd[TUN_OFFSET_BYTES:n+TUN_OFFSET_BYTES], err)
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Now read again
|
// Now read again
|
||||||
@ -132,43 +83,17 @@ func (tun *TunAdapter) handlePacketFrom(from phony.Actor, packet []byte, err err
|
|||||||
// does the work of reading a packet and sending it to the correct tunConn
|
// does the work of reading a packet and sending it to the correct tunConn
|
||||||
func (tun *TunAdapter) _handlePacket(recvd []byte, err error) {
|
func (tun *TunAdapter) _handlePacket(recvd []byte, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.log.Errorln("TUN/TAP iface read error:", err)
|
tun.log.Errorln("TUN iface read error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// If it's a TAP adapter, update the buffer slice so that we no longer
|
|
||||||
// include the ethernet headers
|
|
||||||
offset := 0
|
|
||||||
if tun.iface.IsTAP() {
|
|
||||||
// Set our offset to beyond the ethernet headers
|
|
||||||
offset = tun_ETHER_HEADER_LENGTH
|
|
||||||
// Check first of all that we can go beyond the ethernet headers
|
|
||||||
if len(recvd) <= offset {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Offset the buffer from now on so that we can ignore ethernet frames if
|
// Offset the buffer from now on so that we can ignore ethernet frames if
|
||||||
// they are present
|
// they are present
|
||||||
bs := recvd[offset:]
|
bs := recvd[:]
|
||||||
// Check if the packet is long enough to detect if it's an ICMP packet or not
|
// Check if the packet is long enough to detect if it's an ICMP packet or not
|
||||||
if len(bs) < 7 {
|
if len(bs) < 7 {
|
||||||
tun.log.Traceln("TUN/TAP iface read undersized unknown packet, length:", len(bs))
|
tun.log.Traceln("TUN iface read undersized unknown packet, length:", len(bs))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// If we detect an ICMP packet then hand it to the ICMPv6 module
|
|
||||||
if bs[6] == 58 {
|
|
||||||
// Found an ICMPv6 packet - we need to make sure to give ICMPv6 the full
|
|
||||||
// Ethernet frame rather than just the IPv6 packet as this is needed for
|
|
||||||
// NDP to work correctly
|
|
||||||
if err := tun.icmpv6.ParsePacket(recvd); err == nil {
|
|
||||||
// We acted on the packet in the ICMPv6 module so don't forward or do
|
|
||||||
// anything else with it
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if offset != 0 {
|
|
||||||
// Shift forward to avoid leaking bytes off the front of the slice when we eventually store it
|
|
||||||
bs = append(recvd[:0], bs...)
|
|
||||||
}
|
|
||||||
// From the IP header, work out what our source and destination addresses
|
// From the IP header, work out what our source and destination addresses
|
||||||
// and node IDs are. We will need these in order to work out where to send
|
// and node IDs are. We will need these in order to work out where to send
|
||||||
// the packet
|
// the packet
|
||||||
@ -181,7 +106,7 @@ func (tun *TunAdapter) _handlePacket(recvd []byte, err error) {
|
|||||||
if bs[0]&0xf0 == 0x60 {
|
if bs[0]&0xf0 == 0x60 {
|
||||||
// Check if we have a fully-sized IPv6 header
|
// Check if we have a fully-sized IPv6 header
|
||||||
if len(bs) < 40 {
|
if len(bs) < 40 {
|
||||||
tun.log.Traceln("TUN/TAP iface read undersized ipv6 packet, length:", len(bs))
|
tun.log.Traceln("TUN iface read undersized ipv6 packet, length:", len(bs))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Check the packet size
|
// Check the packet size
|
||||||
@ -195,7 +120,7 @@ func (tun *TunAdapter) _handlePacket(recvd []byte, err error) {
|
|||||||
} else if bs[0]&0xf0 == 0x40 {
|
} else if bs[0]&0xf0 == 0x40 {
|
||||||
// Check if we have a fully-sized IPv4 header
|
// Check if we have a fully-sized IPv4 header
|
||||||
if len(bs) < 20 {
|
if len(bs) < 20 {
|
||||||
tun.log.Traceln("TUN/TAP iface read undersized ipv4 packet, length:", len(bs))
|
tun.log.Traceln("TUN iface read undersized ipv4 packet, length:", len(bs))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Check the packet size
|
// Check the packet size
|
||||||
@ -267,7 +192,7 @@ func (tun *TunAdapter) _handlePacket(recvd []byte, err error) {
|
|||||||
if tc, err = tun._wrap(conn.(*yggdrasil.Conn)); err != nil {
|
if tc, err = tun._wrap(conn.(*yggdrasil.Conn)); err != nil {
|
||||||
// Something went wrong when storing the connection, typically that
|
// Something went wrong when storing the connection, typically that
|
||||||
// something already exists for this address or subnet
|
// something already exists for this address or subnet
|
||||||
tun.log.Debugln("TUN/TAP iface wrap:", err)
|
tun.log.Debugln("TUN iface wrap:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, packet := range packets {
|
for _, packet := range packets {
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
|
|
||||||
"github.com/Arceliar/phony"
|
"github.com/Arceliar/phony"
|
||||||
"github.com/gologme/log"
|
"github.com/gologme/log"
|
||||||
"github.com/yggdrasil-network/water"
|
"golang.zx2c4.com/wireguard/tun"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
@ -28,12 +28,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const tun_IPv6_HEADER_LENGTH = 40
|
const tun_IPv6_HEADER_LENGTH = 40
|
||||||
const tun_ETHER_HEADER_LENGTH = 14
|
|
||||||
|
|
||||||
// TunAdapter represents a running TUN/TAP interface and extends the
|
// TunAdapter represents a running TUN interface and extends the
|
||||||
// yggdrasil.Adapter type. In order to use the TUN/TAP adapter with Yggdrasil,
|
// yggdrasil.Adapter type. In order to use the TUN adapter with Yggdrasil, you
|
||||||
// you should pass this object to the yggdrasil.SetRouterAdapter() function
|
// should pass this object to the yggdrasil.SetRouterAdapter() function before
|
||||||
// before calling yggdrasil.Start().
|
// calling yggdrasil.Start().
|
||||||
type TunAdapter struct {
|
type TunAdapter struct {
|
||||||
core *yggdrasil.Core
|
core *yggdrasil.Core
|
||||||
writer tunWriter
|
writer tunWriter
|
||||||
@ -48,7 +47,7 @@ type TunAdapter struct {
|
|||||||
ckr cryptokey
|
ckr cryptokey
|
||||||
icmpv6 ICMPv6
|
icmpv6 ICMPv6
|
||||||
mtu int
|
mtu int
|
||||||
iface *water.Interface
|
iface tun.Device
|
||||||
phony.Inbox // Currently only used for _handlePacket from the reader, TODO: all the stuff that currently needs a mutex below
|
phony.Inbox // Currently only used for _handlePacket from the reader, TODO: all the stuff that currently needs a mutex below
|
||||||
//mutex sync.RWMutex // Protects the below
|
//mutex sync.RWMutex // Protects the below
|
||||||
addrToConn map[address.Address]*tunConn
|
addrToConn map[address.Address]*tunConn
|
||||||
@ -64,12 +63,12 @@ type TunOptions struct {
|
|||||||
|
|
||||||
// Gets the maximum supported MTU for the platform based on the defaults in
|
// Gets the maximum supported MTU for the platform based on the defaults in
|
||||||
// defaults.GetDefaults().
|
// defaults.GetDefaults().
|
||||||
func getSupportedMTU(mtu int, istapmode bool) int {
|
func getSupportedMTU(mtu int) int {
|
||||||
if mtu < 1280 {
|
if mtu < 1280 {
|
||||||
return 1280
|
return 1280
|
||||||
}
|
}
|
||||||
if mtu > MaximumMTU(istapmode) {
|
if mtu > MaximumMTU() {
|
||||||
return MaximumMTU(istapmode)
|
return MaximumMTU()
|
||||||
}
|
}
|
||||||
return mtu
|
return mtu
|
||||||
}
|
}
|
||||||
@ -77,55 +76,38 @@ func getSupportedMTU(mtu int, istapmode bool) int {
|
|||||||
// Name returns the name of the adapter, e.g. "tun0". On Windows, this may
|
// Name returns the name of the adapter, e.g. "tun0". On Windows, this may
|
||||||
// return a canonical adapter name instead.
|
// return a canonical adapter name instead.
|
||||||
func (tun *TunAdapter) Name() string {
|
func (tun *TunAdapter) Name() string {
|
||||||
return tun.iface.Name()
|
if name, err := tun.iface.Name(); err == nil {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// MTU gets the adapter's MTU. This can range between 1280 and 65535, although
|
// MTU gets the adapter's MTU. This can range between 1280 and 65535, although
|
||||||
// the maximum value is determined by your platform. The returned value will
|
// the maximum value is determined by your platform. The returned value will
|
||||||
// never exceed that of MaximumMTU().
|
// never exceed that of MaximumMTU().
|
||||||
func (tun *TunAdapter) MTU() int {
|
func (tun *TunAdapter) MTU() int {
|
||||||
return getSupportedMTU(tun.mtu, tun.IsTAP())
|
return getSupportedMTU(tun.mtu)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTAP returns true if the adapter is a TAP adapter (Layer 2) or false if it
|
// DefaultName gets the default TUN interface name for your platform.
|
||||||
// is a TUN adapter (Layer 3).
|
|
||||||
func (tun *TunAdapter) IsTAP() bool {
|
|
||||||
return tun.iface.IsTAP()
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultName gets the default TUN/TAP interface name for your platform.
|
|
||||||
func DefaultName() string {
|
func DefaultName() string {
|
||||||
return defaults.GetDefaults().DefaultIfName
|
return defaults.GetDefaults().DefaultIfName
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultMTU gets the default TUN/TAP interface MTU for your platform. This can
|
// DefaultMTU gets the default TUN interface MTU for your platform. This can
|
||||||
// be as high as MaximumMTU(), depending on platform, but is never lower than 1280.
|
// be as high as MaximumMTU(), depending on platform, but is never lower than 1280.
|
||||||
func DefaultMTU() int {
|
func DefaultMTU() int {
|
||||||
ehbytes := 0
|
return defaults.GetDefaults().DefaultIfMTU
|
||||||
if DefaultIsTAP() {
|
|
||||||
ehbytes = tun_ETHER_HEADER_LENGTH
|
|
||||||
}
|
|
||||||
return defaults.GetDefaults().DefaultIfMTU - ehbytes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultIsTAP returns true if the default adapter mode for the current
|
// MaximumMTU returns the maximum supported TUN interface MTU for your
|
||||||
// platform is TAP (Layer 2) and returns false for TUN (Layer 3).
|
|
||||||
func DefaultIsTAP() bool {
|
|
||||||
return defaults.GetDefaults().DefaultIfTAPMode
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaximumMTU returns the maximum supported TUN/TAP interface MTU for your
|
|
||||||
// platform. This can be as high as 65535, depending on platform, but is never
|
// platform. This can be as high as 65535, depending on platform, but is never
|
||||||
// lower than 1280.
|
// lower than 1280.
|
||||||
func MaximumMTU(iftapmode bool) int {
|
func MaximumMTU() int {
|
||||||
ehbytes := 0
|
return defaults.GetDefaults().MaximumIfMTU
|
||||||
if iftapmode {
|
|
||||||
ehbytes = tun_ETHER_HEADER_LENGTH
|
|
||||||
}
|
|
||||||
return defaults.GetDefaults().MaximumIfMTU - ehbytes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialises the TUN/TAP module. You must have acquired a Listener from
|
// Init initialises the TUN module. You must have acquired a Listener from
|
||||||
// the Yggdrasil core before this point and it must not be in use elsewhere.
|
// the Yggdrasil core before this point and it must not be in use elsewhere.
|
||||||
func (tun *TunAdapter) Init(core *yggdrasil.Core, config *config.NodeState, log *log.Logger, options interface{}) error {
|
func (tun *TunAdapter) Init(core *yggdrasil.Core, config *config.NodeState, log *log.Logger, options interface{}) error {
|
||||||
tunoptions, ok := options.(TunOptions)
|
tunoptions, ok := options.(TunOptions)
|
||||||
@ -145,7 +127,7 @@ func (tun *TunAdapter) Init(core *yggdrasil.Core, config *config.NodeState, log
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the setup process for the TUN/TAP adapter. If successful, starts the
|
// Start the setup process for the TUN adapter. If successful, starts the
|
||||||
// reader actor to handle packets on that interface.
|
// reader actor to handle packets on that interface.
|
||||||
func (tun *TunAdapter) Start() error {
|
func (tun *TunAdapter) Start() error {
|
||||||
var err error
|
var err error
|
||||||
@ -157,11 +139,11 @@ func (tun *TunAdapter) Start() error {
|
|||||||
|
|
||||||
func (tun *TunAdapter) _start() error {
|
func (tun *TunAdapter) _start() error {
|
||||||
if tun.isOpen {
|
if tun.isOpen {
|
||||||
return errors.New("TUN/TAP module is already started")
|
return errors.New("TUN module is already started")
|
||||||
}
|
}
|
||||||
current := tun.config.GetCurrent()
|
current := tun.config.GetCurrent()
|
||||||
if tun.config == nil || tun.listener == nil || tun.dialer == nil {
|
if tun.config == nil || tun.listener == nil || tun.dialer == nil {
|
||||||
return errors.New("no configuration available to TUN/TAP")
|
return errors.New("no configuration available to TUN")
|
||||||
}
|
}
|
||||||
var boxPub crypto.BoxPubKey
|
var boxPub crypto.BoxPubKey
|
||||||
boxPubHex, err := hex.DecodeString(current.EncryptionPublicKey)
|
boxPubHex, err := hex.DecodeString(current.EncryptionPublicKey)
|
||||||
@ -174,23 +156,19 @@ func (tun *TunAdapter) _start() error {
|
|||||||
tun.subnet = *address.SubnetForNodeID(nodeID)
|
tun.subnet = *address.SubnetForNodeID(nodeID)
|
||||||
addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1)
|
addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1)
|
||||||
if current.IfName == "none" || current.IfName == "dummy" {
|
if current.IfName == "none" || current.IfName == "dummy" {
|
||||||
tun.log.Debugln("Not starting TUN/TAP as ifname is none or dummy")
|
tun.log.Debugln("Not starting TUN as ifname is none or dummy")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := tun.setup(current.IfName, current.IfTAPMode, addr, current.IfMTU); err != nil {
|
if err := tun.setup(current.IfName, addr, current.IfMTU); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if tun.MTU() != current.IfMTU {
|
if tun.MTU() != current.IfMTU {
|
||||||
tun.log.Warnf("Warning: Interface MTU %d automatically adjusted to %d (supported range is 1280-%d)", current.IfMTU, tun.MTU(), MaximumMTU(tun.IsTAP()))
|
tun.log.Warnf("Warning: Interface MTU %d automatically adjusted to %d (supported range is 1280-%d)", current.IfMTU, tun.MTU(), MaximumMTU())
|
||||||
}
|
}
|
||||||
tun.core.SetMaximumSessionMTU(uint16(tun.MTU()))
|
tun.core.SetMaximumSessionMTU(uint16(tun.MTU()))
|
||||||
tun.isOpen = true
|
tun.isOpen = true
|
||||||
go tun.handler()
|
go tun.handler()
|
||||||
tun.reader.Act(nil, tun.reader._read) // Start the reader
|
tun.reader.Act(nil, tun.reader._read) // Start the reader
|
||||||
tun.icmpv6.Init(tun)
|
|
||||||
if tun.IsTAP() {
|
|
||||||
go tun.icmpv6.Solicit(tun.addr)
|
|
||||||
}
|
|
||||||
tun.ckr.init(tun)
|
tun.ckr.init(tun)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -204,7 +182,7 @@ func (tun *TunAdapter) IsStarted() bool {
|
|||||||
return isOpen
|
return isOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the setup process for the TUN/TAP adapter. If successful, starts the
|
// Start the setup process for the TUN adapter. If successful, starts the
|
||||||
// read/write goroutines to handle packets on that interface.
|
// read/write goroutines to handle packets on that interface.
|
||||||
func (tun *TunAdapter) Stop() error {
|
func (tun *TunAdapter) Stop() error {
|
||||||
var err error
|
var err error
|
||||||
@ -216,7 +194,7 @@ func (tun *TunAdapter) Stop() error {
|
|||||||
|
|
||||||
func (tun *TunAdapter) _stop() error {
|
func (tun *TunAdapter) _stop() error {
|
||||||
tun.isOpen = false
|
tun.isOpen = false
|
||||||
// by TUN/TAP, e.g. readers/writers, sessions
|
// by TUN, e.g. readers/writers, sessions
|
||||||
if tun.iface != nil {
|
if tun.iface != nil {
|
||||||
// Just in case we failed to start up the iface for some reason, this can apparently happen on Windows
|
// Just in case we failed to start up the iface for some reason, this can apparently happen on Windows
|
||||||
tun.iface.Close()
|
tun.iface.Close()
|
||||||
@ -224,16 +202,16 @@ func (tun *TunAdapter) _stop() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateConfig updates the TUN/TAP module with the provided config.NodeConfig
|
// UpdateConfig updates the TUN module with the provided config.NodeConfig
|
||||||
// and then signals the various module goroutines to reconfigure themselves if
|
// and then signals the various module goroutines to reconfigure themselves if
|
||||||
// needed.
|
// needed.
|
||||||
func (tun *TunAdapter) UpdateConfig(config *config.NodeConfig) {
|
func (tun *TunAdapter) UpdateConfig(config *config.NodeConfig) {
|
||||||
tun.log.Debugln("Reloading TUN/TAP configuration...")
|
tun.log.Debugln("Reloading TUN configuration...")
|
||||||
|
|
||||||
// Replace the active configuration with the supplied one
|
// Replace the active configuration with the supplied one
|
||||||
tun.config.Replace(*config)
|
tun.config.Replace(*config)
|
||||||
|
|
||||||
// If the MTU has changed in the TUN/TAP module then this is where we would
|
// If the MTU has changed in the TUN module then this is where we would
|
||||||
// tell the router so that updated session pings can be sent. However, we
|
// tell the router so that updated session pings can be sent. However, we
|
||||||
// don't currently update the MTU of the adapter once it has been created so
|
// don't currently update the MTU of the adapter once it has been created so
|
||||||
// this doesn't actually happen in the real world yet.
|
// this doesn't actually happen in the real world yet.
|
||||||
@ -248,14 +226,14 @@ func (tun *TunAdapter) handler() error {
|
|||||||
// Accept the incoming connection
|
// Accept the incoming connection
|
||||||
conn, err := tun.listener.Accept()
|
conn, err := tun.listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.log.Errorln("TUN/TAP connection accept error:", err)
|
tun.log.Errorln("TUN connection accept error:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
phony.Block(tun, func() {
|
phony.Block(tun, func() {
|
||||||
if _, err := tun._wrap(conn.(*yggdrasil.Conn)); err != nil {
|
if _, err := tun._wrap(conn.(*yggdrasil.Conn)); err != nil {
|
||||||
// Something went wrong when storing the connection, typically that
|
// Something went wrong when storing the connection, typically that
|
||||||
// something already exists for this address or subnet
|
// something already exists for this address or subnet
|
||||||
tun.log.Debugln("TUN/TAP handler wrap:", err)
|
tun.log.Debugln("TUN handler wrap:", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// +build openbsd freebsd netbsd
|
// +build openbsd freebsd
|
||||||
|
|
||||||
package tuntap
|
package tuntap
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/water"
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SIOCSIFADDR_IN6 = (0x80000000) | ((288 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 12
|
const SIOCSIFADDR_IN6 = (0x80000000) | ((288 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 12
|
||||||
@ -72,34 +72,18 @@ type in6_ifreq_lifetime struct {
|
|||||||
ifru_addrlifetime in6_addrlifetime
|
ifru_addrlifetime in6_addrlifetime
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the IPv6 address of the utun adapter. On all BSD platforms (FreeBSD,
|
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
||||||
// OpenBSD, NetBSD) an attempt is made to set the adapter properties by using
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
// a system socket and making syscalls to the kernel. This is not refined though
|
iface, err := wgtun.CreateTUN(ifname, mtu)
|
||||||
// and often doesn't work (if at all), therefore if a call fails, it resorts
|
|
||||||
// to calling "ifconfig" instead.
|
|
||||||
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
|
||||||
var config water.Config
|
|
||||||
if ifname[:4] == "auto" {
|
|
||||||
ifname = "/dev/tap0"
|
|
||||||
}
|
|
||||||
if len(ifname) < 9 {
|
|
||||||
panic("TUN/TAP name must be in format /dev/tunX or /dev/tapX")
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case iftapmode || ifname[:8] == "/dev/tap":
|
|
||||||
config = water.Config{DeviceType: water.TAP}
|
|
||||||
case !iftapmode || ifname[:8] == "/dev/tun":
|
|
||||||
panic("TUN mode is not currently supported on this platform, please use TAP instead")
|
|
||||||
default:
|
|
||||||
panic("TUN/TAP name must be in format /dev/tunX or /dev/tapX")
|
|
||||||
}
|
|
||||||
config.Name = ifname
|
|
||||||
iface, err := water.New(config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tun.iface = iface
|
tun.iface = iface
|
||||||
tun.mtu = getSupportedMTU(mtu, iftapmode)
|
if mtu, err := iface.MTU(); err == nil {
|
||||||
|
tun.mtu = getSupportedMTU(mtu)
|
||||||
|
} else {
|
||||||
|
tun.mtu = 0
|
||||||
|
}
|
||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,13 +98,13 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Friendly output
|
// Friendly output
|
||||||
tun.log.Infof("Interface name: %s", tun.iface.Name())
|
tun.log.Infof("Interface name: %s", tun.Name())
|
||||||
tun.log.Infof("Interface IPv6: %s", addr)
|
tun.log.Infof("Interface IPv6: %s", addr)
|
||||||
tun.log.Infof("Interface MTU: %d", tun.mtu)
|
tun.log.Infof("Interface MTU: %d", tun.mtu)
|
||||||
|
|
||||||
// Create the MTU request
|
// Create the MTU request
|
||||||
var ir in6_ifreq_mtu
|
var ir in6_ifreq_mtu
|
||||||
copy(ir.ifr_name[:], tun.iface.Name())
|
copy(ir.ifr_name[:], tun.Name())
|
||||||
ir.ifru_mtu = int(tun.mtu)
|
ir.ifru_mtu = int(tun.mtu)
|
||||||
|
|
||||||
// Set the MTU
|
// Set the MTU
|
||||||
@ -129,7 +113,7 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
tun.log.Errorf("Error in SIOCSIFMTU: %v", errno)
|
tun.log.Errorf("Error in SIOCSIFMTU: %v", errno)
|
||||||
|
|
||||||
// Fall back to ifconfig to set the MTU
|
// Fall back to ifconfig to set the MTU
|
||||||
cmd := exec.Command("ifconfig", tun.iface.Name(), "mtu", string(tun.mtu))
|
cmd := exec.Command("ifconfig", tun.Name(), "mtu", string(tun.mtu))
|
||||||
tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
|
tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -141,7 +125,7 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
// Create the address request
|
// Create the address request
|
||||||
// FIXME: I don't work!
|
// FIXME: I don't work!
|
||||||
var ar in6_ifreq_addr
|
var ar in6_ifreq_addr
|
||||||
copy(ar.ifr_name[:], tun.iface.Name())
|
copy(ar.ifr_name[:], tun.Name())
|
||||||
ar.ifru_addr.sin6_len = uint8(unsafe.Sizeof(ar.ifru_addr))
|
ar.ifru_addr.sin6_len = uint8(unsafe.Sizeof(ar.ifru_addr))
|
||||||
ar.ifru_addr.sin6_family = unix.AF_INET6
|
ar.ifru_addr.sin6_family = unix.AF_INET6
|
||||||
parts := strings.Split(strings.Split(addr, "/")[0], ":")
|
parts := strings.Split(strings.Split(addr, "/")[0], ":")
|
||||||
@ -158,7 +142,7 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
tun.log.Errorf("Error in SIOCSIFADDR_IN6: %v", errno)
|
tun.log.Errorf("Error in SIOCSIFADDR_IN6: %v", errno)
|
||||||
|
|
||||||
// Fall back to ifconfig to set the address
|
// Fall back to ifconfig to set the address
|
||||||
cmd := exec.Command("ifconfig", tun.iface.Name(), "inet6", addr)
|
cmd := exec.Command("ifconfig", tun.Name(), "inet6", addr)
|
||||||
tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
|
tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -12,22 +12,24 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
water "github.com/yggdrasil-network/water"
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configures the "utun" adapter with the correct IPv6 address and MTU.
|
// Configures the "utun" adapter with the correct IPv6 address and MTU.
|
||||||
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
if iftapmode {
|
if ifname == "auto" {
|
||||||
tun.log.Warnln("Warning: TAP mode is not supported on this platform, defaulting to TUN")
|
ifname = "utun"
|
||||||
iftapmode = false
|
|
||||||
}
|
}
|
||||||
config := water.Config{DeviceType: water.TUN}
|
iface, err := wgtun.CreateTUN(ifname, mtu)
|
||||||
iface, err := water.New(config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tun.iface = iface
|
tun.iface = iface
|
||||||
tun.mtu = getSupportedMTU(mtu, iftapmode)
|
if mtu, err := iface.MTU(); err == nil {
|
||||||
|
tun.mtu = getSupportedMTU(mtu)
|
||||||
|
} else {
|
||||||
|
tun.mtu = 0
|
||||||
|
}
|
||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +82,7 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ar in6_aliasreq
|
var ar in6_aliasreq
|
||||||
copy(ar.ifra_name[:], tun.iface.Name())
|
copy(ar.ifra_name[:], tun.Name())
|
||||||
|
|
||||||
ar.ifra_prefixmask.sin6_len = uint8(unsafe.Sizeof(ar.ifra_prefixmask))
|
ar.ifra_prefixmask.sin6_len = uint8(unsafe.Sizeof(ar.ifra_prefixmask))
|
||||||
b := make([]byte, 16)
|
b := make([]byte, 16)
|
||||||
@ -104,7 +106,7 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
ar.ifra_lifetime.ia6t_pltime = darwin_ND6_INFINITE_LIFETIME
|
ar.ifra_lifetime.ia6t_pltime = darwin_ND6_INFINITE_LIFETIME
|
||||||
|
|
||||||
var ir ifreq
|
var ir ifreq
|
||||||
copy(ir.ifr_name[:], tun.iface.Name())
|
copy(ir.ifr_name[:], tun.Name())
|
||||||
ir.ifru_mtu = uint32(tun.mtu)
|
ir.ifru_mtu = uint32(tun.mtu)
|
||||||
|
|
||||||
tun.log.Infof("Interface name: %s", ar.ifra_name)
|
tun.log.Infof("Interface name: %s", ar.ifra_name)
|
||||||
|
@ -6,31 +6,24 @@ package tuntap
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
water "github.com/yggdrasil-network/water"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configures the TAP adapter with the correct IPv6 address and MTU.
|
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
||||||
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
var config water.Config
|
if ifname == "auto" {
|
||||||
if iftapmode {
|
ifname = "\000"
|
||||||
config = water.Config{DeviceType: water.TAP}
|
|
||||||
} else {
|
|
||||||
config = water.Config{DeviceType: water.TUN}
|
|
||||||
}
|
}
|
||||||
if ifname != "" && ifname != "auto" {
|
iface, err := wgtun.CreateTUN(ifname, mtu)
|
||||||
config.Name = ifname
|
|
||||||
}
|
|
||||||
iface, err := water.New(config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tun.iface = iface
|
tun.iface = iface
|
||||||
tun.mtu = getSupportedMTU(mtu, iftapmode)
|
if mtu, err := iface.MTU(); err == nil {
|
||||||
// Friendly output
|
tun.mtu = getSupportedMTU(mtu)
|
||||||
tun.log.Infof("Interface name: %s", tun.iface.Name())
|
} else {
|
||||||
tun.log.Infof("Interface IPv6: %s", addr)
|
tun.mtu = 0
|
||||||
tun.log.Infof("Interface MTU: %d", tun.mtu)
|
}
|
||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +36,7 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
nlintf, err := netlink.LinkByName(tun.iface.Name())
|
nlintf, err := netlink.LinkByName(tun.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -56,5 +49,9 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
if err := netlink.LinkSetUp(nlintf); err != nil {
|
if err := netlink.LinkSetUp(nlintf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Friendly output
|
||||||
|
tun.log.Infof("Interface name: %s", tun.Name())
|
||||||
|
tun.log.Infof("Interface IPv6: %s", addr)
|
||||||
|
tun.log.Infof("Interface MTU: %d", tun.mtu)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,32 @@
|
|||||||
// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd,!mobile
|
// +build !linux,!darwin,!windows,!openbsd,!freebsd,!mobile
|
||||||
|
|
||||||
package tuntap
|
package tuntap
|
||||||
|
|
||||||
import water "github.com/yggdrasil-network/water"
|
|
||||||
|
|
||||||
// This is to catch unsupported platforms
|
// This is to catch unsupported platforms
|
||||||
// If your platform supports tun devices, you could try configuring it manually
|
// If your platform supports tun devices, you could try configuring it manually
|
||||||
|
|
||||||
// Creates the TUN/TAP adapter, if supported by the Water library. Note that
|
import (
|
||||||
// no guarantees are made at this point on an unsupported platform.
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
)
|
||||||
var config water.Config
|
|
||||||
if iftapmode {
|
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
||||||
config = water.Config{DeviceType: water.TAP}
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
} else {
|
iface, err := wgtun.CreateTUN(ifname, mtu)
|
||||||
config = water.Config{DeviceType: water.TUN}
|
|
||||||
}
|
|
||||||
iface, err := water.New(config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tun.iface = iface
|
tun.iface = iface
|
||||||
tun.mtu = getSupportedMTU(mtu, iftapmode)
|
if mtu, err := iface.MTU(); err == nil {
|
||||||
|
tun.mtu = getSupportedMTU(mtu)
|
||||||
|
} else {
|
||||||
|
tun.mtu = 0
|
||||||
|
}
|
||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't know how to set the IPv6 address on an unknown platform, therefore
|
// We don't know how to set the IPv6 address on an unknown platform, therefore
|
||||||
// write about it to stdout and don't try to do anything further.
|
// write about it to stdout and don't try to do anything further.
|
||||||
func (tun *TunAdapter) setupAddress(addr string) error {
|
func (tun *TunAdapter) setupAddress(addr string) error {
|
||||||
tun.log.Warnln("Warning: Platform not supported, you must set the address of", tun.iface.Name(), "to", addr)
|
tun.log.Warnln("Warning: Platform not supported, you must set the address of", tun.Name(), "to", addr)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,116 +1,150 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
package tuntap
|
package tuntap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"log"
|
||||||
"os/exec"
|
"net"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
water "github.com/yggdrasil-network/water"
|
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
|
||||||
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
|
"golang.zx2c4.com/wireguard/windows/elevate"
|
||||||
|
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is to catch Windows platforms
|
// This is to catch Windows platforms
|
||||||
|
|
||||||
// Configures the TAP adapter with the correct IPv6 address and MTU. On Windows
|
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
||||||
// we don't make use of a direct operating system API to do this - we instead
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
// delegate the hard work to "netsh".
|
|
||||||
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
|
||||||
if !iftapmode {
|
|
||||||
tun.log.Warnln("Warning: TUN mode is not supported on this platform, defaulting to TAP")
|
|
||||||
iftapmode = true
|
|
||||||
}
|
|
||||||
config := water.Config{DeviceType: water.TAP}
|
|
||||||
config.PlatformSpecificParams.ComponentID = "tap0901"
|
|
||||||
config.PlatformSpecificParams.Network = "169.254.0.1/32"
|
|
||||||
if ifname == "auto" {
|
if ifname == "auto" {
|
||||||
config.PlatformSpecificParams.InterfaceName = ""
|
ifname = defaults.GetDefaults().DefaultIfName
|
||||||
} else {
|
|
||||||
config.PlatformSpecificParams.InterfaceName = ifname
|
|
||||||
}
|
}
|
||||||
iface, err := water.New(config)
|
return elevate.DoAsSystem(func() error {
|
||||||
if err != nil {
|
var err error
|
||||||
|
var iface wgtun.Device
|
||||||
|
var guid windows.GUID
|
||||||
|
if guid, err = windows.GUIDFromString("{8f59971a-7872-4aa6-b2eb-061fc4e9d0a7}"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if iface.Name() == "" {
|
if iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, mtu); err != nil {
|
||||||
return errors.New("unable to find TAP adapter with component ID " + config.PlatformSpecificParams.ComponentID)
|
|
||||||
}
|
|
||||||
// Reset the adapter - this invalidates iface so we'll need to get a new one
|
|
||||||
cmd := exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=DISABLED")
|
|
||||||
tun.log.Debugln("netsh command:", strings.Join(cmd.Args, " "))
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
tun.log.Errorln("Windows netsh failed:", err)
|
|
||||||
tun.log.Traceln(string(output))
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second) // FIXME artifical delay to give netsh time to take effect
|
|
||||||
// Bring the interface back up
|
|
||||||
cmd = exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=ENABLED")
|
|
||||||
tun.log.Debugln("netsh command:", strings.Join(cmd.Args, " "))
|
|
||||||
output, err = cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
tun.log.Errorln("Windows netsh failed:", err)
|
|
||||||
tun.log.Traceln(string(output))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second) // FIXME artifical delay to give netsh time to take effect
|
|
||||||
// Get a new iface
|
|
||||||
iface, err = water.New(config)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
tun.iface = iface
|
tun.iface = iface
|
||||||
tun.mtu = getSupportedMTU(mtu, iftapmode)
|
if err = tun.setupAddress(addr); err != nil {
|
||||||
err = tun.setupMTU(tun.mtu)
|
tun.log.Errorln("Failed to set up TUN address:", err)
|
||||||
if err != nil {
|
return err
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
// Friendly output
|
if err = tun.setupMTU(getSupportedMTU(mtu)); err != nil {
|
||||||
tun.log.Infof("Interface name: %s", tun.iface.Name())
|
tun.log.Errorln("Failed to set up TUN MTU:", err)
|
||||||
tun.log.Infof("Interface IPv6: %s", addr)
|
return err
|
||||||
tun.log.Infof("Interface MTU: %d", tun.mtu)
|
}
|
||||||
return tun.setupAddress(addr)
|
if mtu, err = iface.MTU(); err == nil {
|
||||||
|
tun.mtu = mtu
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the MTU of the TAP adapter.
|
// Sets the MTU of the TAP adapter.
|
||||||
func (tun *TunAdapter) setupMTU(mtu int) error {
|
func (tun *TunAdapter) setupMTU(mtu int) error {
|
||||||
if tun.iface == nil || tun.iface.Name() == "" {
|
if tun.iface == nil || tun.Name() == "" {
|
||||||
return errors.New("Can't configure MTU as TAP adapter is not present")
|
return errors.New("Can't configure MTU as TUN adapter is not present")
|
||||||
}
|
}
|
||||||
// Set MTU
|
if intf, ok := tun.iface.(*wgtun.NativeTun); ok {
|
||||||
cmd := exec.Command("netsh", "interface", "ipv6", "set", "subinterface",
|
luid := winipcfg.LUID(intf.LUID())
|
||||||
fmt.Sprintf("interface=%s", tun.iface.Name()),
|
ipfamily, err := luid.IPInterface(windows.AF_INET6)
|
||||||
fmt.Sprintf("mtu=%d", mtu),
|
|
||||||
"store=active")
|
|
||||||
tun.log.Debugln("netsh command:", strings.Join(cmd.Args, " "))
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.log.Errorln("Windows netsh failed:", err)
|
|
||||||
tun.log.Traceln(string(output))
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second) // FIXME artifical delay to give netsh time to take effect
|
|
||||||
|
ipfamily.NLMTU = uint32(mtu)
|
||||||
|
intf.ForceMTU(int(ipfamily.NLMTU))
|
||||||
|
ipfamily.UseAutomaticMetric = false
|
||||||
|
ipfamily.Metric = 0
|
||||||
|
ipfamily.DadTransmits = 0
|
||||||
|
ipfamily.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
|
||||||
|
|
||||||
|
if err := ipfamily.Set(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the IPv6 address of the TAP adapter.
|
// Sets the IPv6 address of the TAP adapter.
|
||||||
func (tun *TunAdapter) setupAddress(addr string) error {
|
func (tun *TunAdapter) setupAddress(addr string) error {
|
||||||
if tun.iface == nil || tun.iface.Name() == "" {
|
if tun.iface == nil || tun.Name() == "" {
|
||||||
return errors.New("Can't configure IPv6 address as TAP adapter is not present")
|
return errors.New("Can't configure IPv6 address as TUN adapter is not present")
|
||||||
|
}
|
||||||
|
if intf, ok := tun.iface.(*wgtun.NativeTun); ok {
|
||||||
|
if ipaddr, ipnet, err := net.ParseCIDR(addr); err == nil {
|
||||||
|
luid := winipcfg.LUID(intf.LUID())
|
||||||
|
addresses := append([]net.IPNet{}, net.IPNet{
|
||||||
|
IP: ipaddr,
|
||||||
|
Mask: ipnet.Mask,
|
||||||
|
})
|
||||||
|
|
||||||
|
err := luid.SetIPAddressesForFamily(windows.AF_INET6, addresses)
|
||||||
|
if err == windows.ERROR_OBJECT_ALREADY_EXISTS {
|
||||||
|
cleanupAddressesOnDisconnectedInterfaces(windows.AF_INET6, addresses)
|
||||||
|
err = luid.SetIPAddressesForFamily(windows.AF_INET6, addresses)
|
||||||
}
|
}
|
||||||
// Set address
|
|
||||||
cmd := exec.Command("netsh", "interface", "ipv6", "add", "address",
|
|
||||||
fmt.Sprintf("interface=%s", tun.iface.Name()),
|
|
||||||
fmt.Sprintf("addr=%s", addr),
|
|
||||||
"store=active")
|
|
||||||
tun.log.Debugln("netsh command:", strings.Join(cmd.Args, " "))
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.log.Errorln("Windows netsh failed:", err)
|
|
||||||
tun.log.Traceln(string(output))
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second) // FIXME artifical delay to give netsh time to take effect
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return errors.New("unable to get NativeTUN")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cleanupAddressesOnDisconnectedInterfaces
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
func cleanupAddressesOnDisconnectedInterfaces(family winipcfg.AddressFamily, addresses []net.IPNet) {
|
||||||
|
if len(addresses) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
includedInAddresses := func(a net.IPNet) bool {
|
||||||
|
// TODO: this makes the whole algorithm O(n^2). But we can't stick net.IPNet in a Go hashmap. Bummer!
|
||||||
|
for _, addr := range addresses {
|
||||||
|
ip := addr.IP
|
||||||
|
if ip4 := ip.To4(); ip4 != nil {
|
||||||
|
ip = ip4
|
||||||
|
}
|
||||||
|
mA, _ := addr.Mask.Size()
|
||||||
|
mB, _ := a.Mask.Size()
|
||||||
|
if bytes.Equal(ip, a.IP) && mA == mB {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
interfaces, err := winipcfg.GetAdaptersAddresses(family, winipcfg.GAAFlagDefault)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, iface := range interfaces {
|
||||||
|
if iface.OperStatus == winipcfg.IfOperStatusUp {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for address := iface.FirstUnicastAddress; address != nil; address = address.Next {
|
||||||
|
ip := address.Address.IP()
|
||||||
|
ipnet := net.IPNet{IP: ip, Mask: net.CIDRMask(int(address.OnLinkPrefixLength), 8*len(ip))}
|
||||||
|
if includedInAddresses(ipnet) {
|
||||||
|
log.Printf("Cleaning up stale address %s from interface ‘%s’", ipnet.String(), iface.FriendlyName())
|
||||||
|
iface.LUID.DeleteIPAddress(ipnet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user