Showing preview only (1,406K chars total). Download the full file or copy to clipboard to get everything.
Repository: slackhq/nebula
Branch: master
Commit: 1aa1a0476f6b
Files: 216
Total size: 1.3 MB
Directory structure:
gitextract_aqr65ra4/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.yml
│ │ └── config.yml
│ ├── dependabot.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── gofmt.yml
│ ├── release.yml
│ ├── smoke/
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ ├── build-relay.sh
│ │ ├── build.sh
│ │ ├── genconfig.sh
│ │ ├── smoke-relay.sh
│ │ ├── smoke-vagrant.sh
│ │ ├── smoke.sh
│ │ ├── vagrant-freebsd-amd64/
│ │ │ └── Vagrantfile
│ │ ├── vagrant-linux-386/
│ │ │ └── Vagrantfile
│ │ ├── vagrant-linux-amd64-ipv6disable/
│ │ │ └── Vagrantfile
│ │ ├── vagrant-netbsd-amd64/
│ │ │ └── Vagrantfile
│ │ └── vagrant-openbsd-amd64/
│ │ └── Vagrantfile
│ ├── smoke-extra.yml
│ ├── smoke.yml
│ └── test.yml
├── .gitignore
├── .golangci.yaml
├── AUTHORS
├── CHANGELOG.md
├── CODEOWNERS
├── LICENSE
├── LOGGING.md
├── Makefile
├── README.md
├── SECURITY.md
├── allow_list.go
├── allow_list_test.go
├── bits.go
├── bits_test.go
├── boring.go
├── calculated_remote.go
├── calculated_remote_test.go
├── cert/
│ ├── Makefile
│ ├── README.md
│ ├── asn1.go
│ ├── ca_pool.go
│ ├── ca_pool_test.go
│ ├── cert.go
│ ├── cert_v1.go
│ ├── cert_v1.pb.go
│ ├── cert_v1.proto
│ ├── cert_v1_test.go
│ ├── cert_v2.asn1
│ ├── cert_v2.go
│ ├── cert_v2_test.go
│ ├── crypto.go
│ ├── crypto_test.go
│ ├── errors.go
│ ├── helper_test.go
│ ├── p256/
│ │ ├── p256.go
│ │ └── p256_test.go
│ ├── pem.go
│ ├── pem_test.go
│ ├── sign.go
│ └── sign_test.go
├── cert_test/
│ └── cert.go
├── cmd/
│ ├── nebula/
│ │ ├── main.go
│ │ ├── notify_linux.go
│ │ └── notify_notlinux.go
│ ├── nebula-cert/
│ │ ├── ca.go
│ │ ├── ca_test.go
│ │ ├── keygen.go
│ │ ├── keygen_test.go
│ │ ├── main.go
│ │ ├── main_test.go
│ │ ├── p11_cgo.go
│ │ ├── p11_stub.go
│ │ ├── passwords.go
│ │ ├── passwords_test.go
│ │ ├── print.go
│ │ ├── print_test.go
│ │ ├── sign.go
│ │ ├── sign_test.go
│ │ ├── test_darwin.go
│ │ ├── test_linux.go
│ │ ├── test_windows.go
│ │ ├── verify.go
│ │ └── verify_test.go
│ └── nebula-service/
│ ├── logs_generic.go
│ ├── logs_windows.go
│ ├── main.go
│ └── service.go
├── config/
│ ├── config.go
│ └── config_test.go
├── connection_manager.go
├── connection_manager_test.go
├── connection_state.go
├── control.go
├── control_test.go
├── control_tester.go
├── dist/
│ ├── windows/
│ │ └── wintun/
│ │ ├── LICENSE.txt
│ │ ├── README.md
│ │ └── include/
│ │ └── wintun.h
│ └── wireshark/
│ └── nebula.lua
├── dns_server.go
├── dns_server_test.go
├── docker/
│ ├── Dockerfile
│ └── README.md
├── e2e/
│ ├── doc.go
│ ├── handshakes_test.go
│ ├── helpers_test.go
│ ├── router/
│ │ ├── doc.go
│ │ ├── hostmap.go
│ │ └── router.go
│ └── tunnels_test.go
├── examples/
│ ├── config.yml
│ ├── go_service/
│ │ └── main.go
│ └── service_scripts/
│ ├── nebula.init.d.sh
│ ├── nebula.open-rc
│ ├── nebula.plist
│ └── nebula.service
├── firewall/
│ ├── cache.go
│ └── packet.go
├── firewall.go
├── firewall_test.go
├── go.mod
├── go.sum
├── handshake_ix.go
├── handshake_manager.go
├── handshake_manager_test.go
├── header/
│ ├── header.go
│ └── header_test.go
├── hostmap.go
├── hostmap_test.go
├── hostmap_tester.go
├── inside.go
├── inside_bsd.go
├── inside_generic.go
├── interface.go
├── iputil/
│ ├── packet.go
│ └── packet_test.go
├── lighthouse.go
├── lighthouse_test.go
├── logger.go
├── main.go
├── message_metrics.go
├── nebula.pb.go
├── nebula.proto
├── noise.go
├── noiseutil/
│ ├── boring.go
│ ├── boring_test.go
│ ├── nist.go
│ ├── notboring.go
│ ├── notboring_test.go
│ └── pkcs11.go
├── notboring.go
├── outside.go
├── outside_test.go
├── overlay/
│ ├── device.go
│ ├── route.go
│ ├── route_test.go
│ ├── tun.go
│ ├── tun_android.go
│ ├── tun_darwin.go
│ ├── tun_disabled.go
│ ├── tun_freebsd.go
│ ├── tun_ios.go
│ ├── tun_linux.go
│ ├── tun_linux_test.go
│ ├── tun_netbsd.go
│ ├── tun_notwin.go
│ ├── tun_openbsd.go
│ ├── tun_tester.go
│ ├── tun_windows.go
│ └── user.go
├── pkclient/
│ ├── pkclient.go
│ ├── pkclient_cgo.go
│ └── pkclient_stub.go
├── pki.go
├── punchy.go
├── punchy_test.go
├── relay_manager.go
├── remote_list.go
├── remote_list_test.go
├── routing/
│ ├── balance.go
│ ├── balance_test.go
│ ├── gateway.go
│ └── gateway_test.go
├── service/
│ ├── listener.go
│ ├── service.go
│ └── service_test.go
├── ssh.go
├── sshd/
│ ├── command.go
│ ├── server.go
│ ├── session.go
│ └── writer.go
├── stats.go
├── test/
│ ├── assert.go
│ ├── logger.go
│ └── tun.go
├── timeout.go
├── timeout_test.go
├── udp/
│ ├── conn.go
│ ├── errors.go
│ ├── udp_android.go
│ ├── udp_bsd.go
│ ├── udp_darwin.go
│ ├── udp_generic.go
│ ├── udp_linux.go
│ ├── udp_linux_32.go
│ ├── udp_linux_64.go
│ ├── udp_netbsd.go
│ ├── udp_rio_windows.go
│ ├── udp_tester.go
│ └── udp_windows.go
├── util/
│ ├── error.go
│ └── error_test.go
└── wintun/
├── device.go
└── tun.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.yml
================================================
name: "\U0001F41B Bug Report"
description: Report an issue or possible bug
title: "\U0001F41B BUG:"
labels: []
assignees: []
body:
- type: markdown
attributes:
value: |
### Thank you for taking the time to file a bug report!
Please fill out this form as completely as possible.
- type: input
id: version
attributes:
label: What version of `nebula` are you using? (`nebula -version`)
placeholder: 0.0.0
validations:
required: true
- type: input
id: os
attributes:
label: What operating system are you using?
description: iOS and Android specific issues belong in the [mobile_nebula](https://github.com/DefinedNet/mobile_nebula) repo.
placeholder: Linux, Mac, Windows
validations:
required: true
- type: textarea
id: description
attributes:
label: Describe the Bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Logs from affected hosts
description: |
Please provide logs from ALL affected hosts during the time of the issue. If you do not provide logs we will be unable to assist you!
[Learn how to find Nebula logs here.](https://nebula.defined.net/docs/guides/viewing-nebula-logs/)
Improve formatting by using <code>```</code> at the beginning and end of each log block.
value: |
```
```
validations:
required: true
- type: textarea
id: configs
attributes:
label: Config files from affected hosts
description: |
Provide config files for all affected hosts.
Improve formatting by using <code>```</code> at the beginning and end of each config file.
value: |
```
```
validations:
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
- name: 💨 Performance Issues
url: https://github.com/slackhq/nebula/discussions/new/choose
about: 'We ask that you create a discussion instead of an issue for performance-related questions. This allows us to have a more open conversation about the issue and helps us to better understand the problem.'
- name: 📄 Documentation Issues
url: https://github.com/definednet/nebula-docs
about: "If you've found an issue with the website documentation, please file it in the nebula-docs repository."
- name: 📱 Mobile Nebula Issues
url: https://github.com/definednet/mobile_nebula
about: "If you're using the mobile Nebula app and have found an issue, please file it in the mobile_nebula repository."
- name: 📘 Documentation
url: https://nebula.defined.net/docs/
about: 'The documentation is the best place to start if you are new to Nebula.'
- name: 💁 Support/Chat
url: https://join.slack.com/t/nebulaoss/shared_invite/zt-39pk4xopc-CUKlGcb5Z39dQ0cK1v7ehA
about: 'For faster support, join us on Slack for assistance!'
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
groups:
golang-x-dependencies:
patterns:
- "golang.org/x/*"
zx2c4-dependencies:
patterns:
- "golang.zx2c4.com/*"
protobuf-dependencies:
patterns:
- "github.com/golang/protobuf"
- "google.golang.org/protobuf"
================================================
FILE: .github/pull_request_template.md
================================================
<!--
Thank you for taking the time to submit a pull request!
Please be sure to provide a clear description of what you're trying to achieve with the change.
- If you're submitting a new feature, please explain how to use it and document any new config options in the example config.
- If you're submitting a bugfix, please link the related issue or describe the circumstances surrounding the issue.
- If you're changing a default, explain why you believe the new default is appropriate for most users.
P.S. If you're only updating the README or other docs, please file a pull request here instead: https://github.com/DefinedNet/nebula-docs
-->
================================================
FILE: .github/workflows/gofmt.yml
================================================
name: gofmt
on:
push:
branches:
- master
pull_request:
paths:
- '.github/workflows/gofmt.yml'
- '**.go'
jobs:
gofmt:
name: Run gofmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
check-latest: true
- name: Install goimports
run: |
go install golang.org/x/tools/cmd/goimports@latest
- name: gofmt
run: |
if [ "$(find . -iname '*.go' | grep -v '\.pb\.go$' | xargs goimports -l)" ]
then
find . -iname '*.go' | grep -v '\.pb\.go$' | xargs goimports -d
exit 1
fi
================================================
FILE: .github/workflows/release.yml
================================================
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]*'
name: Create release and upload binaries
jobs:
build-linux:
name: Build Linux/BSD All
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
check-latest: true
- name: Build
run: |
make BUILD_NUMBER="${GITHUB_REF#refs/tags/v}" release-linux release-freebsd release-openbsd release-netbsd
mkdir release
mv build/*.tar.gz release
- name: Upload artifacts
uses: actions/upload-artifact@v6
with:
name: linux-latest
path: release
build-windows:
name: Build Windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
check-latest: true
- name: Build
run: |
echo $Env:GITHUB_REF.Substring(11)
mkdir build\windows-amd64
$Env:GOARCH = "amd64"
go build -trimpath -ldflags "-X main.Build=$($Env:GITHUB_REF.Substring(11))" -o build\windows-amd64\nebula.exe ./cmd/nebula-service
go build -trimpath -ldflags "-X main.Build=$($Env:GITHUB_REF.Substring(11))" -o build\windows-amd64\nebula-cert.exe ./cmd/nebula-cert
mkdir build\windows-arm64
$Env:GOARCH = "arm64"
go build -trimpath -ldflags "-X main.Build=$($Env:GITHUB_REF.Substring(11))" -o build\windows-arm64\nebula.exe ./cmd/nebula-service
go build -trimpath -ldflags "-X main.Build=$($Env:GITHUB_REF.Substring(11))" -o build\windows-arm64\nebula-cert.exe ./cmd/nebula-cert
mkdir build\dist\windows
mv dist\windows\wintun build\dist\windows\
- name: Upload artifacts
uses: actions/upload-artifact@v6
with:
name: windows-latest
path: build
build-darwin:
name: Build Universal Darwin
env:
HAS_SIGNING_CREDS: ${{ secrets.AC_USERNAME != '' }}
runs-on: macos-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
check-latest: true
- name: Import certificates
if: env.HAS_SIGNING_CREDS == 'true'
uses: Apple-Actions/import-codesign-certs@v6
with:
p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}
p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }}
- name: Build, sign, and notarize
env:
AC_USERNAME: ${{ secrets.AC_USERNAME }}
AC_PASSWORD: ${{ secrets.AC_PASSWORD }}
run: |
rm -rf release
mkdir release
make BUILD_NUMBER="${GITHUB_REF#refs/tags/v}" service build/darwin-amd64/nebula build/darwin-amd64/nebula-cert
make BUILD_NUMBER="${GITHUB_REF#refs/tags/v}" service build/darwin-arm64/nebula build/darwin-arm64/nebula-cert
lipo -create -output ./release/nebula ./build/darwin-amd64/nebula ./build/darwin-arm64/nebula
lipo -create -output ./release/nebula-cert ./build/darwin-amd64/nebula-cert ./build/darwin-arm64/nebula-cert
if [ -n "$AC_USERNAME" ]; then
codesign -s "10BC1FDDEB6CE753550156C0669109FAC49E4D1E" -f -v --timestamp --options=runtime -i "net.defined.nebula" ./release/nebula
codesign -s "10BC1FDDEB6CE753550156C0669109FAC49E4D1E" -f -v --timestamp --options=runtime -i "net.defined.nebula-cert" ./release/nebula-cert
fi
zip -j release/nebula-darwin.zip release/nebula-cert release/nebula
if [ -n "$AC_USERNAME" ]; then
xcrun notarytool submit ./release/nebula-darwin.zip --team-id "576H3XS7FP" --apple-id "$AC_USERNAME" --password "$AC_PASSWORD" --wait
fi
- name: Upload artifacts
uses: actions/upload-artifact@v6
with:
name: darwin-latest
path: ./release/*
build-docker:
name: Create and Upload Docker Images
# Technically we only need build-linux to succeed, but if any platforms fail we'll
# want to investigate and restart the build
needs: [build-linux, build-darwin, build-windows]
runs-on: ubuntu-latest
env:
HAS_DOCKER_CREDS: ${{ vars.DOCKERHUB_USERNAME != '' && secrets.DOCKERHUB_TOKEN != '' }}
# XXX It's not possible to write a conditional here, so instead we do it on every step
#if: ${{ env.HAS_DOCKER_CREDS == 'true' }}
steps:
# Be sure to checkout the code before downloading artifacts, or they will
# be overwritten
- name: Checkout code
if: ${{ env.HAS_DOCKER_CREDS == 'true' }}
uses: actions/checkout@v6
- name: Download artifacts
if: ${{ env.HAS_DOCKER_CREDS == 'true' }}
uses: actions/download-artifact@v7
with:
name: linux-latest
path: artifacts
- name: Login to Docker Hub
if: ${{ env.HAS_DOCKER_CREDS == 'true' }}
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
if: ${{ env.HAS_DOCKER_CREDS == 'true' }}
uses: docker/setup-buildx-action@v3
- name: Build and push images
if: ${{ env.HAS_DOCKER_CREDS == 'true' }}
env:
DOCKER_IMAGE_REPO: ${{ vars.DOCKER_IMAGE_REPO || 'nebulaoss/nebula' }}
DOCKER_IMAGE_TAG: ${{ vars.DOCKER_IMAGE_TAG || 'latest' }}
run: |
mkdir -p build/linux-{amd64,arm64}
tar -zxvf artifacts/nebula-linux-amd64.tar.gz -C build/linux-amd64/
tar -zxvf artifacts/nebula-linux-arm64.tar.gz -C build/linux-arm64/
docker buildx build . --push -f docker/Dockerfile --platform linux/amd64,linux/arm64 --tag "${DOCKER_IMAGE_REPO}:${DOCKER_IMAGE_TAG}" --tag "${DOCKER_IMAGE_REPO}:${GITHUB_REF#refs/tags/v}"
release:
name: Create and Upload Release
needs: [build-linux, build-darwin, build-windows]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Download artifacts
uses: actions/download-artifact@v7
with:
path: artifacts
- name: Zip Windows
run: |
cd artifacts/windows-latest
cp windows-amd64/* .
zip -r nebula-windows-amd64.zip nebula.exe nebula-cert.exe dist
cp windows-arm64/* .
zip -r nebula-windows-arm64.zip nebula.exe nebula-cert.exe dist
- name: Create sha256sum
run: |
cd artifacts
for dir in linux-latest darwin-latest windows-latest
do
(
cd $dir
if [ "$dir" = windows-latest ]
then
sha256sum <windows-amd64/nebula.exe | sed 's=-$=nebula-windows-amd64.zip/nebula.exe='
sha256sum <windows-amd64/nebula-cert.exe | sed 's=-$=nebula-windows-amd64.zip/nebula-cert.exe='
sha256sum <windows-arm64/nebula.exe | sed 's=-$=nebula-windows-arm64.zip/nebula.exe='
sha256sum <windows-arm64/nebula-cert.exe | sed 's=-$=nebula-windows-arm64.zip/nebula-cert.exe='
sha256sum nebula-windows-amd64.zip
sha256sum nebula-windows-arm64.zip
elif [ "$dir" = darwin-latest ]
then
sha256sum <nebula-darwin.zip | sed 's=-$=nebula-darwin.zip='
sha256sum <nebula | sed 's=-$=nebula-darwin.zip/nebula='
sha256sum <nebula-cert | sed 's=-$=nebula-darwin.zip/nebula-cert='
else
for v in *.tar.gz
do
sha256sum $v
tar zxf $v --to-command='sh -c "sha256sum | sed s=-$='$v'/$TAR_FILENAME="'
done
fi
)
done | sort -k 2 >SHASUM256.txt
- name: Create Release
id: create_release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd artifacts
gh release create \
--verify-tag \
--title "Release ${{ github.ref_name }}" \
"${{ github.ref_name }}" \
SHASUM256.txt *-latest/*.zip *-latest/*.tar.gz
================================================
FILE: .github/workflows/smoke/.gitignore
================================================
/build
================================================
FILE: .github/workflows/smoke/Dockerfile
================================================
FROM ubuntu:jammy
RUN apt-get update && apt-get install -y iputils-ping ncat tcpdump
ADD ./build /nebula
WORKDIR /nebula
ENTRYPOINT ["/nebula/nebula"]
================================================
FILE: .github/workflows/smoke/build-relay.sh
================================================
#!/bin/sh
set -e -x
rm -rf ./build
mkdir ./build
(
cd build
cp ../../../../build/linux-amd64/nebula .
cp ../../../../build/linux-amd64/nebula-cert .
HOST="lighthouse1" AM_LIGHTHOUSE=true ../genconfig.sh >lighthouse1.yml <<EOF
relay:
am_relay: true
EOF
export LIGHTHOUSES="192.168.100.1 172.17.0.2:4242"
export REMOTE_ALLOW_LIST='{"172.17.0.4/32": false, "172.17.0.5/32": false}'
HOST="host2" ../genconfig.sh >host2.yml <<EOF
relay:
relays:
- 192.168.100.1
EOF
export REMOTE_ALLOW_LIST='{"172.17.0.3/32": false}'
HOST="host3" ../genconfig.sh >host3.yml
HOST="host4" ../genconfig.sh >host4.yml <<EOF
relay:
use_relays: false
EOF
../../../../nebula-cert ca -name "Smoke Test"
../../../../nebula-cert sign -name "lighthouse1" -groups "lighthouse,lighthouse1" -ip "192.168.100.1/24"
../../../../nebula-cert sign -name "host2" -groups "host,host2" -ip "192.168.100.2/24"
../../../../nebula-cert sign -name "host3" -groups "host,host3" -ip "192.168.100.3/24"
../../../../nebula-cert sign -name "host4" -groups "host,host4" -ip "192.168.100.4/24"
)
docker build -t nebula:smoke-relay .
================================================
FILE: .github/workflows/smoke/build.sh
================================================
#!/bin/sh
set -e -x
rm -rf ./build
mkdir ./build
# TODO: Assumes your docker bridge network is a /24, and the first container that launches will be .1
# - We could make this better by launching the lighthouse first and then fetching what IP it is.
NET="$(docker network inspect bridge -f '{{ range .IPAM.Config }}{{ .Subnet }}{{ end }}' | cut -d. -f1-3)"
(
cd build
cp ../../../../build/linux-amd64/nebula .
cp ../../../../build/linux-amd64/nebula-cert .
if [ "$1" ]
then
cp "../../../../build/$1/nebula" "$1-nebula"
fi
HOST="lighthouse1" \
AM_LIGHTHOUSE=true \
../genconfig.sh >lighthouse1.yml
HOST="host2" \
LIGHTHOUSES="192.168.100.1 $NET.2:4242" \
../genconfig.sh >host2.yml
HOST="host3" \
LIGHTHOUSES="192.168.100.1 $NET.2:4242" \
INBOUND='[{"port": "any", "proto": "icmp", "group": "lighthouse"}]' \
../genconfig.sh >host3.yml
HOST="host4" \
LIGHTHOUSES="192.168.100.1 $NET.2:4242" \
OUTBOUND='[{"port": "any", "proto": "icmp", "group": "lighthouse"}]' \
../genconfig.sh >host4.yml
../../../../nebula-cert ca -curve "${CURVE:-25519}" -name "Smoke Test"
../../../../nebula-cert sign -name "lighthouse1" -groups "lighthouse,lighthouse1" -ip "192.168.100.1/24"
../../../../nebula-cert sign -name "host2" -groups "host,host2" -ip "192.168.100.2/24"
../../../../nebula-cert sign -name "host3" -groups "host,host3" -ip "192.168.100.3/24"
../../../../nebula-cert sign -name "host4" -groups "host,host4" -ip "192.168.100.4/24"
)
docker build -t "nebula:${NAME:-smoke}" .
================================================
FILE: .github/workflows/smoke/genconfig.sh
================================================
#!/bin/sh
set -e
FIREWALL_ALL='[{"port": "any", "proto": "any", "host": "any"}]'
if [ "$STATIC_HOSTS" ] || [ "$LIGHTHOUSES" ]
then
echo "static_host_map:"
echo "$STATIC_HOSTS" | while read -r NEBULA_IP STATIC
do
[ -z "$NEBULA_IP" ] || echo " '$NEBULA_IP': ['$STATIC']"
done
echo "$LIGHTHOUSES" | while read -r NEBULA_IP STATIC
do
[ -z "$NEBULA_IP" ] || echo " '$NEBULA_IP': ['$STATIC']"
done
echo
fi
lighthouse_hosts() {
if [ "$LIGHTHOUSES" ]
then
echo
echo "$LIGHTHOUSES" | while read -r NEBULA_IP STATIC
do
echo " - '$NEBULA_IP'"
done
else
echo "[]"
fi
}
cat <<EOF
pki:
ca: ca.crt
cert: ${HOST}.crt
key: ${HOST}.key
lighthouse:
am_lighthouse: ${AM_LIGHTHOUSE:-false}
hosts: $(lighthouse_hosts)
remote_allow_list: ${REMOTE_ALLOW_LIST}
listen:
host: 0.0.0.0
port: ${LISTEN_PORT:-4242}
tun:
dev: ${TUN_DEV:-tun0}
firewall:
inbound_action: reject
outbound_action: reject
outbound: ${OUTBOUND:-$FIREWALL_ALL}
inbound: ${INBOUND:-$FIREWALL_ALL}
$(test -t 0 || cat)
EOF
================================================
FILE: .github/workflows/smoke/smoke-relay.sh
================================================
#!/bin/bash
set -e -x
set -o pipefail
mkdir -p logs
cleanup() {
echo
echo " *** cleanup"
echo
set +e
if [ "$(jobs -r)" ]
then
docker kill lighthouse1 host2 host3 host4
fi
}
trap cleanup EXIT
docker run --name lighthouse1 --rm nebula:smoke-relay -config lighthouse1.yml -test
docker run --name host2 --rm nebula:smoke-relay -config host2.yml -test
docker run --name host3 --rm nebula:smoke-relay -config host3.yml -test
docker run --name host4 --rm nebula:smoke-relay -config host4.yml -test
docker run --name lighthouse1 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm nebula:smoke-relay -config lighthouse1.yml 2>&1 | tee logs/lighthouse1 | sed -u 's/^/ [lighthouse1] /' &
sleep 1
docker run --name host2 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm nebula:smoke-relay -config host2.yml 2>&1 | tee logs/host2 | sed -u 's/^/ [host2] /' &
sleep 1
docker run --name host3 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm nebula:smoke-relay -config host3.yml 2>&1 | tee logs/host3 | sed -u 's/^/ [host3] /' &
sleep 1
docker run --name host4 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm nebula:smoke-relay -config host4.yml 2>&1 | tee logs/host4 | sed -u 's/^/ [host4] /' &
sleep 1
set +x
echo
echo " *** Testing ping from lighthouse1"
echo
set -x
docker exec lighthouse1 ping -c1 192.168.100.2
docker exec lighthouse1 ping -c1 192.168.100.3
docker exec lighthouse1 ping -c1 192.168.100.4
set +x
echo
echo " *** Testing ping from host2"
echo
set -x
docker exec host2 ping -c1 192.168.100.1
# Should fail because no relay configured in this direction
! docker exec host2 ping -c1 192.168.100.3 -w5 || exit 1
! docker exec host2 ping -c1 192.168.100.4 -w5 || exit 1
set +x
echo
echo " *** Testing ping from host3"
echo
set -x
docker exec host3 ping -c1 192.168.100.1
docker exec host3 ping -c1 192.168.100.2
docker exec host3 ping -c1 192.168.100.4
set +x
echo
echo " *** Testing ping from host4"
echo
set -x
docker exec host4 ping -c1 192.168.100.1
# Should fail because relays not allowed
! docker exec host4 ping -c1 192.168.100.2 -w5 || exit 1
docker exec host4 ping -c1 192.168.100.3
docker exec host4 sh -c 'kill 1'
docker exec host3 sh -c 'kill 1'
docker exec host2 sh -c 'kill 1'
docker exec lighthouse1 sh -c 'kill 1'
sleep 5
if [ "$(jobs -r)" ]
then
echo "nebula still running after SIGTERM sent" >&2
exit 1
fi
================================================
FILE: .github/workflows/smoke/smoke-vagrant.sh
================================================
#!/bin/bash
set -e -x
set -o pipefail
export VAGRANT_CWD="$PWD/vagrant-$1"
mkdir -p logs
cleanup() {
echo
echo " *** cleanup"
echo
set +e
if [ "$(jobs -r)" ]
then
docker kill lighthouse1 host2
fi
vagrant destroy -f
}
trap cleanup EXIT
CONTAINER="nebula:${NAME:-smoke}"
docker run --name lighthouse1 --rm "$CONTAINER" -config lighthouse1.yml -test
docker run --name host2 --rm "$CONTAINER" -config host2.yml -test
vagrant up
vagrant ssh -c "cd /nebula && /nebula/$1-nebula -config host3.yml -test" -- -T
docker run --name lighthouse1 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm "$CONTAINER" -config lighthouse1.yml 2>&1 | tee logs/lighthouse1 | sed -u 's/^/ [lighthouse1] /' &
sleep 1
docker run --name host2 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm "$CONTAINER" -config host2.yml 2>&1 | tee logs/host2 | sed -u 's/^/ [host2] /' &
sleep 1
vagrant ssh -c "cd /nebula && sudo sh -c 'echo \$\$ >/nebula/pid && exec /nebula/$1-nebula -config host3.yml'" 2>&1 -- -T | tee logs/host3 | sed -u 's/^/ [host3] /' &
sleep 15
# grab tcpdump pcaps for debugging
docker exec lighthouse1 tcpdump -i nebula1 -q -w - -U 2>logs/lighthouse1.inside.log >logs/lighthouse1.inside.pcap &
docker exec lighthouse1 tcpdump -i eth0 -q -w - -U 2>logs/lighthouse1.outside.log >logs/lighthouse1.outside.pcap &
docker exec host2 tcpdump -i nebula1 -q -w - -U 2>logs/host2.inside.log >logs/host2.inside.pcap &
docker exec host2 tcpdump -i eth0 -q -w - -U 2>logs/host2.outside.log >logs/host2.outside.pcap &
# vagrant ssh -c "tcpdump -i nebula1 -q -w - -U" 2>logs/host3.inside.log >logs/host3.inside.pcap &
# vagrant ssh -c "tcpdump -i eth0 -q -w - -U" 2>logs/host3.outside.log >logs/host3.outside.pcap &
#docker exec host2 ncat -nklv 0.0.0.0 2000 &
#vagrant ssh -c "ncat -nklv 0.0.0.0 2000" &
#docker exec host2 ncat -e '/usr/bin/echo host2' -nkluv 0.0.0.0 3000 &
#vagrant ssh -c "ncat -e '/usr/bin/echo host3' -nkluv 0.0.0.0 3000" &
set +x
echo
echo " *** Testing ping from lighthouse1"
echo
set -x
docker exec lighthouse1 ping -c1 192.168.100.2
docker exec lighthouse1 ping -c1 192.168.100.3
set +x
echo
echo " *** Testing ping from host2"
echo
set -x
docker exec host2 ping -c1 192.168.100.1
# Should fail because not allowed by host3 inbound firewall
! docker exec host2 ping -c1 192.168.100.3 -w5 || exit 1
#set +x
#echo
#echo " *** Testing ncat from host2"
#echo
#set -x
# Should fail because not allowed by host3 inbound firewall
#! docker exec host2 ncat -nzv -w5 192.168.100.3 2000 || exit 1
#! docker exec host2 ncat -nzuv -w5 192.168.100.3 3000 | grep -q host3 || exit 1
set +x
echo
echo " *** Testing ping from host3"
echo
set -x
vagrant ssh -c "ping -c1 192.168.100.1" -- -T
vagrant ssh -c "ping -c1 192.168.100.2" -- -T
#set +x
#echo
#echo " *** Testing ncat from host3"
#echo
#set -x
#vagrant ssh -c "ncat -nzv -w5 192.168.100.2 2000"
#vagrant ssh -c "ncat -nzuv -w5 192.168.100.2 3000" | grep -q host2
vagrant ssh -c "sudo xargs kill </nebula/pid" -- -T
docker exec host2 sh -c 'kill 1'
docker exec lighthouse1 sh -c 'kill 1'
sleep 1
if [ "$(jobs -r)" ]
then
echo "nebula still running after SIGTERM sent" >&2
exit 1
fi
================================================
FILE: .github/workflows/smoke/smoke.sh
================================================
#!/bin/bash
set -e -x
set -o pipefail
mkdir -p logs
cleanup() {
echo
echo " *** cleanup"
echo
set +e
if [ "$(jobs -r)" ]
then
docker kill lighthouse1 host2 host3 host4
fi
}
trap cleanup EXIT
CONTAINER="nebula:${NAME:-smoke}"
docker run --name lighthouse1 --rm "$CONTAINER" -config lighthouse1.yml -test
docker run --name host2 --rm "$CONTAINER" -config host2.yml -test
docker run --name host3 --rm "$CONTAINER" -config host3.yml -test
docker run --name host4 --rm "$CONTAINER" -config host4.yml -test
docker run --name lighthouse1 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm "$CONTAINER" -config lighthouse1.yml 2>&1 | tee logs/lighthouse1 | sed -u 's/^/ [lighthouse1] /' &
sleep 1
docker run --name host2 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm "$CONTAINER" -config host2.yml 2>&1 | tee logs/host2 | sed -u 's/^/ [host2] /' &
sleep 1
docker run --name host3 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm "$CONTAINER" -config host3.yml 2>&1 | tee logs/host3 | sed -u 's/^/ [host3] /' &
sleep 1
docker run --name host4 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm "$CONTAINER" -config host4.yml 2>&1 | tee logs/host4 | sed -u 's/^/ [host4] /' &
sleep 1
# grab tcpdump pcaps for debugging
docker exec lighthouse1 tcpdump -i tun0 -q -w - -U 2>logs/lighthouse1.inside.log >logs/lighthouse1.inside.pcap &
docker exec lighthouse1 tcpdump -i eth0 -q -w - -U 2>logs/lighthouse1.outside.log >logs/lighthouse1.outside.pcap &
docker exec host2 tcpdump -i tun0 -q -w - -U 2>logs/host2.inside.log >logs/host2.inside.pcap &
docker exec host2 tcpdump -i eth0 -q -w - -U 2>logs/host2.outside.log >logs/host2.outside.pcap &
docker exec host3 tcpdump -i tun0 -q -w - -U 2>logs/host3.inside.log >logs/host3.inside.pcap &
docker exec host3 tcpdump -i eth0 -q -w - -U 2>logs/host3.outside.log >logs/host3.outside.pcap &
docker exec host4 tcpdump -i tun0 -q -w - -U 2>logs/host4.inside.log >logs/host4.inside.pcap &
docker exec host4 tcpdump -i eth0 -q -w - -U 2>logs/host4.outside.log >logs/host4.outside.pcap &
docker exec host2 ncat -nklv 0.0.0.0 2000 &
docker exec host3 ncat -nklv 0.0.0.0 2000 &
docker exec host4 ncat -nkluv 0.0.0.0 4000 &
docker exec host2 ncat -e '/usr/bin/echo host2' -nkluv 0.0.0.0 3000 &
docker exec host3 ncat -e '/usr/bin/echo host3' -nkluv 0.0.0.0 3000 &
set +x
echo
echo " *** Testing ping from lighthouse1"
echo
set -x
docker exec lighthouse1 ping -c1 192.168.100.2
docker exec lighthouse1 ping -c1 192.168.100.3
set +x
echo
echo " *** Testing ping from host2"
echo
set -x
docker exec host2 ping -c1 192.168.100.1
# Should fail because not allowed by host3 inbound firewall
! docker exec host2 ping -c1 192.168.100.3 -w5 || exit 1
set +x
echo
echo " *** Testing ncat from host2"
echo
set -x
# Should fail because not allowed by host3 inbound firewall
! docker exec host2 ncat -nzv -w5 192.168.100.3 2000 || exit 1
! docker exec host2 ncat -nzuv -w5 192.168.100.3 3000 | grep -q host3 || exit 1
set +x
echo
echo " *** Testing ping from host3"
echo
set -x
docker exec host3 ping -c1 192.168.100.1
docker exec host3 ping -c1 192.168.100.2
set +x
echo
echo " *** Testing ncat from host3"
echo
set -x
docker exec host3 ncat -nzv -w5 192.168.100.2 2000
docker exec host3 ncat -nzuv -w5 192.168.100.2 3000 | grep -q host2
set +x
echo
echo " *** Testing ping from host4"
echo
set -x
docker exec host4 ping -c1 192.168.100.1
# Should fail because not allowed by host4 outbound firewall
! docker exec host4 ping -c1 192.168.100.2 -w5 || exit 1
! docker exec host4 ping -c1 192.168.100.3 -w5 || exit 1
set +x
echo
echo " *** Testing ncat from host4"
echo
set -x
# Should fail because not allowed by host4 outbound firewall
! docker exec host4 ncat -nzv -w5 192.168.100.2 2000 || exit 1
! docker exec host4 ncat -nzv -w5 192.168.100.3 2000 || exit 1
! docker exec host4 ncat -nzuv -w5 192.168.100.2 3000 | grep -q host2 || exit 1
! docker exec host4 ncat -nzuv -w5 192.168.100.3 3000 | grep -q host3 || exit 1
set +x
echo
echo " *** Testing conntrack"
echo
set -x
# host2 speaking to host4 on UDP 4000 should allow it to reply, when firewall rules would normally not permit this
docker exec host2 sh -c "/usr/bin/echo host2 | ncat -nuv 192.168.100.4 4000"
docker exec host2 ncat -e '/usr/bin/echo helloagainfromhost2' -nkluv 0.0.0.0 4000 &
docker exec host4 sh -c "/usr/bin/echo host4 | ncat -nuv 192.168.100.2 4000"
docker exec host4 sh -c 'kill 1'
docker exec host3 sh -c 'kill 1'
docker exec host2 sh -c 'kill 1'
docker exec lighthouse1 sh -c 'kill 1'
sleep 5
if [ "$(jobs -r)" ]
then
echo "nebula still running after SIGTERM sent" >&2
exit 1
fi
================================================
FILE: .github/workflows/smoke/vagrant-freebsd-amd64/Vagrantfile
================================================
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "generic/freebsd14"
config.vm.synced_folder "../build", "/nebula", type: "rsync"
end
================================================
FILE: .github/workflows/smoke/vagrant-linux-386/Vagrantfile
================================================
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial32"
config.vm.synced_folder "../build", "/nebula"
end
================================================
FILE: .github/workflows/smoke/vagrant-linux-amd64-ipv6disable/Vagrantfile
================================================
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/jammy64"
config.vm.synced_folder "../build", "/nebula"
config.vm.provision :shell do |shell|
shell.inline = <<-EOF
sed -i 's/GRUB_CMDLINE_LINUX=""/GRUB_CMDLINE_LINUX="ipv6.disable=1"/' /etc/default/grub
update-grub
EOF
shell.privileged = true
shell.reboot = true
end
end
================================================
FILE: .github/workflows/smoke/vagrant-netbsd-amd64/Vagrantfile
================================================
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "generic/netbsd9"
config.vm.synced_folder "../build", "/nebula", type: "rsync"
end
================================================
FILE: .github/workflows/smoke/vagrant-openbsd-amd64/Vagrantfile
================================================
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "generic/openbsd7"
config.vm.synced_folder "../build", "/nebula", type: "rsync"
end
================================================
FILE: .github/workflows/smoke-extra.yml
================================================
name: smoke-extra
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, labeled, reopened]
paths:
- '.github/workflows/smoke**'
- '**Makefile'
- '**.go'
- '**.proto'
- 'go.mod'
- 'go.sum'
jobs:
smoke-extra:
if: github.ref == 'refs/heads/master' || contains(github.event.pull_request.labels.*.name, 'smoke-test-extra')
name: Run extra smoke tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
check-latest: true
- name: add hashicorp source
run: wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg && echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
- name: workaround AMD-V issue # https://github.com/cri-o/packaging/pull/306
run: sudo rmmod kvm_amd
- name: install vagrant
run: sudo apt-get update && sudo apt-get install -y vagrant virtualbox
- name: freebsd-amd64
run: make smoke-vagrant/freebsd-amd64
- name: openbsd-amd64
run: make smoke-vagrant/openbsd-amd64
- name: netbsd-amd64
run: make smoke-vagrant/netbsd-amd64
- name: linux-386
run: make smoke-vagrant/linux-386
- name: linux-amd64-ipv6disable
run: make smoke-vagrant/linux-amd64-ipv6disable
timeout-minutes: 30
================================================
FILE: .github/workflows/smoke.yml
================================================
name: smoke
on:
push:
branches:
- master
pull_request:
paths:
- '.github/workflows/smoke**'
- '**Makefile'
- '**.go'
- '**.proto'
- 'go.mod'
- 'go.sum'
jobs:
smoke:
name: Run multi node smoke test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
check-latest: true
- name: build
run: make bin-docker CGO_ENABLED=1 BUILD_ARGS=-race
- name: setup docker image
working-directory: ./.github/workflows/smoke
run: ./build.sh
- name: run smoke
working-directory: ./.github/workflows/smoke
run: ./smoke.sh
- name: setup relay docker image
working-directory: ./.github/workflows/smoke
run: ./build-relay.sh
- name: run smoke relay
working-directory: ./.github/workflows/smoke
run: ./smoke-relay.sh
- name: setup docker image for P256
working-directory: ./.github/workflows/smoke
run: NAME="smoke-p256" CURVE=P256 ./build.sh
- name: run smoke-p256
working-directory: ./.github/workflows/smoke
run: NAME="smoke-p256" ./smoke.sh
timeout-minutes: 10
================================================
FILE: .github/workflows/test.yml
================================================
name: Build and test
on:
push:
branches:
- master
pull_request:
paths:
- '.github/workflows/test.yml'
- '**Makefile'
- '**.go'
- '**.proto'
- 'go.mod'
- 'go.sum'
jobs:
test-linux:
name: Build all and test on ubuntu-linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
check-latest: true
- name: Build
run: make all
- name: Vet
run: make vet
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.5
- name: Test
run: make test
- name: End 2 end
run: make e2evv
- name: Build test mobile
run: make build-test-mobile
- uses: actions/upload-artifact@v6
with:
name: e2e packet flow linux-latest
path: e2e/mermaid/linux-latest
if-no-files-found: warn
test-linux-boringcrypto:
name: Build and test on linux with boringcrypto
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
check-latest: true
- name: Build
run: make bin-boringcrypto
- name: Test
run: make test-boringcrypto
- name: End 2 end
run: make e2e GOEXPERIMENT=boringcrypto CGO_ENABLED=1 TEST_ENV="TEST_LOGS=1" TEST_FLAGS="-v -ldflags -checklinkname=0"
test-linux-pkcs11:
name: Build and test on linux with pkcs11
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
check-latest: true
- name: Build
run: make bin-pkcs11
- name: Test
run: make test-pkcs11
test:
name: Build and test on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, macos-latest]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
check-latest: true
- name: Build nebula
run: go build ./cmd/nebula
- name: Build nebula-cert
run: go build ./cmd/nebula-cert
- name: Vet
run: make vet
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.5
- name: Test
run: make test
- name: End 2 end
run: make e2evv
- uses: actions/upload-artifact@v6
with:
name: e2e packet flow ${{ matrix.os }}
path: e2e/mermaid/${{ matrix.os }}
if-no-files-found: warn
================================================
FILE: .gitignore
================================================
/nebula
/nebula-cert
/nebula-arm
/nebula-arm6
/nebula-darwin
/nebula.exe
/nebula-cert.exe
**/coverage.out
**/cover.out
/cpu.pprof
/build
/*.tar.gz
/e2e/mermaid/
**.crt
**.key
**.pem
**.pub
!/examples/quickstart-vagrant/ansible/roles/nebula/files/vagrant-test-ca.key
!/examples/quickstart-vagrant/ansible/roles/nebula/files/vagrant-test-ca.crt
================================================
FILE: .golangci.yaml
================================================
version: "2"
linters:
default: none
enable:
- testifylint
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
================================================
FILE: AUTHORS
================================================
# This is the official list of Nebula authors for copyright purposes.
# Names should be added to this file as:
# Name or Organization <email address>
# The email address is not required for organizations.
Slack Technologies, Inc.
Nate Brown <nbrown.us@gmail.com>
Ryan Huber <rhuber@gmail.com>
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.10.3] - 2026-02-06
### Security
- Fix an issue where blocklist bypass is possible when using curve P256 since the signature can have 2 valid representations.
Both fingerprint representations will be tested against the blocklist.
Any newly issued P256 based certificates will have their signature clamped to the low-s form.
Nebula will assert the low-s signature form when validating certificates in a future version. [GHSA-69x3-g4r3-p962](https://github.com/slackhq/nebula/security/advisories/GHSA-69x3-g4r3-p962)
### Changed
- Improve error reporting if nebula fails to start due to a tun device naming issue. (#1588)
## [1.10.2] - 2026-01-21
### Fixed
- Fix panic when using `use_system_route_table` that was introduced in v1.10.1. (#1580)
### Changed
- Fix some typos in comments. (#1582)
- Dependency updates. (#1581)
## [1.10.1] - 2026-01-16
See the [v1.10.1](https://github.com/slackhq/nebula/milestone/26?closed=1) milestone for a complete list of changes.
### Fixed
- Fix a bug where an unsafe route derived from the system route table could be lost on a config reload. (#1573)
- Fix the PEM banner for ECDSA P256 public keys. (#1552)
- Fix a regression on Windows from 1.9.x where nebula could fall back to a less performant UDP listener if
non-critical ioctls failed. (#1568)
- Fix a bug in handshake processing when a peer sends an unexpected public key. (#1566)
### Added
- Add a config option to control accepting `recv_error` packets which defaults to `always`. (#1569)
### Changed
- Various dependency updates. (#1541, #1549, #1550, #1557, #1558, #1560, #1561, #1570, #1571)
## [1.10.0] - 2025-12-04
See the [v1.10.0](https://github.com/slackhq/nebula/milestone/16?closed=1) milestone for a complete list of changes.
### Added
- Support for ipv6 and multiple ipv4/6 addresses in the overlay.
A new v2 ASN.1 based certificate format.
Certificates now have a unified interface for external implementations.
(#1212, #1216, #1345, #1359, #1381, #1419, #1464, #1466, #1451, #1476, #1467, #1481, #1399, #1488, #1492, #1495, #1468, #1521, #1535, #1538)
- Add the ability to mark packets on linux to better target nebula packets in iptables/nftables. (#1331)
- Add ECMP support for `unsafe_routes`. (#1332)
- PKCS11 support for P256 keys when built with `pkcs11` tag (#1153, #1482)
### Changed
- **NOTE**: `default_local_cidr_any` now defaults to false, meaning that any firewall rule
intended to target an `unsafe_routes` entry must explicitly declare it via the
`local_cidr` field. This is almost always the intended behavior. This flag is
deprecated and will be removed in a future release. (#1373)
- Improve logging when a relay is in use on an inbound packet. (#1533)
- Avoid fatal errors if `rountines` is > 1 on systems that don't support more than 1 routine. (#1531)
- Log a warning if a firewall rule contains an `any` that negates a more restrictive filter. (#1513)
- Accept encrypted CA passphrase from an environment variable. (#1421)
- Allow handshaking with any trusted remote. (#1509)
- Log only the count of blocklisted certificate fingerprints instead of the entire list. (#1525)
- Don't fatal when the ssh server is unable to be configured successfully. (#1520)
- Update to build against go v1.25. (#1483)
- Allow projects using `nebula` as a library with userspace networking to configure the `logger` and build version. (#1239)
- Upgrade to `yaml.v3`. (#1148, #1371, #1438, #1478)
### Fixed
- Fix a potential bug with udp ipv4 only on darwin. (#1532)
- Improve lost packet statistics. (#1441, #1537)
- Honor `remote_allow_list` in hole punch response. (#1186)
- Fix a panic when `tun.use_system_route_table` is `true` and a route lacks a destination. (#1437)
- Fix an issue when `tun.use_system_route_table: true` could result in heavy CPU utilization when many thousands of routes
are present. (#1326)
- Fix tests for 32 bit machines. (#1394)
- Fix a possible 32bit integer underflow in config handling. (#1353)
- Fix moving a udp address from one vpn address to another in the `static_host_map`
which could cause rapid re-handshaking with an incorrect remote. (#1259)
- Improve smoke tests in environments where the docker network is not the default. (#1347)
## [1.9.7] - 2025-10-10
### Security
- Fix an issue where Nebula could incorrectly accept and process a packet from an erroneous source IP when the sender's
certificate is configured with unsafe_routes (cert v1/v2) or multiple IPs (cert v2). (#1494)
### Changed
- Disable sending `recv_error` messages when a packet is received outside the allowable counter window. (#1459)
- Improve error messages and remove some unnecessary fatal conditions in the Windows and generic udp listener. (#1453)
## [1.9.6] - 2025-7-15
### Added
- Support dropping inactive tunnels. This is disabled by default in this release but can be enabled with `tunnels.drop_inactive`. See example config for more details. (#1413)
### Fixed
- Fix Darwin freeze due to presence of some Network Extensions (#1426)
- Ensure the same relay tunnel is always used when multiple relay tunnels are present (#1422)
- Fix Windows freeze due to ICMP error handling (#1412)
- Fix relay migration panic (#1403)
## [1.9.5] - 2024-12-05
### Added
- Gracefully ignore v2 certificates. (#1282)
### Fixed
- Fix relays that refuse to re-establish after one of the remote tunnel pairs breaks. (#1277)
## [1.9.4] - 2024-09-09
### Added
- Support UDP dialing with gVisor. (#1181)
### Changed
- Make some Nebula state programmatically available via control object. (#1188)
- Switch internal representation of IPs to netip, to prepare for IPv6 support
in the overlay. (#1173)
- Minor build and cleanup changes. (#1171, #1164, #1162)
- Various dependency updates. (#1195, #1190, #1174, #1168, #1167, #1161, #1147, #1146)
### Fixed
- Fix a bug on big endian hosts, like mips. (#1194)
- Fix a rare panic if a local index collision happens. (#1191)
- Fix integer wraparound in the calculation of handshake timeouts on 32-bit targets. (#1185)
## [1.9.3] - 2024-06-06
### Fixed
- Initialize messageCounter to 2 instead of verifying later. (#1156)
## [1.9.2] - 2024-06-03
### Fixed
- Ensure messageCounter is set before handshake is complete. (#1154)
## [1.9.1] - 2024-05-29
### Fixed
- Fixed a potential deadlock in GetOrHandshake. (#1151)
## [1.9.0] - 2024-05-07
### Deprecated
- This release adds a new setting `default_local_cidr_any` that defaults to
true to match previous behavior, but will default to false in the next
release (1.10). When set to false, `local_cidr` is matched correctly for
firewall rules on hosts acting as unsafe routers, and should be set for any
firewall rules you want to allow unsafe route hosts to access. See the issue
and example config for more details. (#1071, #1099)
### Added
- Nebula now has an official Docker image `nebulaoss/nebula` that is
distroless and contains just the `nebula` and `nebula-cert` binaries. You
can find it here: https://hub.docker.com/r/nebulaoss/nebula (#1037)
- Experimental binaries for `loong64` are now provided. (#1003)
- Added example service script for OpenRC. (#711)
- The SSH daemon now supports inlined host keys. (#1054)
- The SSH daemon now supports certificates with `sshd.trusted_cas`. (#1098)
### Changed
- Config setting `tun.unsafe_routes` is now reloadable. (#1083)
- Small documentation and internal improvements. (#1065, #1067, #1069, #1108,
#1109, #1111, #1135)
- Various dependency updates. (#1139, #1138, #1134, #1133, #1126, #1123, #1110,
#1094, #1092, #1087, #1086, #1085, #1072, #1063, #1059, #1055, #1053, #1047,
#1046, #1034, #1022)
### Removed
- Support for the deprecated `local_range` option has been removed. Please
change to `preferred_ranges` (which is also now reloadable). (#1043)
- We are now building with go1.22, which means that for Windows you need at
least Windows 10 or Windows Server 2016. This is because support for earlier
versions was removed in Go 1.21. See https://go.dev/doc/go1.21#windows (#981)
- Removed vagrant example, as it was unmaintained. (#1129)
- Removed Fedora and Arch nebula.service files, as they are maintained in the
upstream repos. (#1128, #1132)
- Remove the TCP round trip tracking metrics, as they never had correct data
and were an experiment to begin with. (#1114)
### Fixed
- Fixed a potential deadlock introduced in 1.8.1. (#1112)
- Fixed support for Linux when IPv6 has been disabled at the OS level. (#787)
- DNS will return NXDOMAIN now when there are no results. (#845)
- Allow `::` in `lighthouse.dns.host`. (#1115)
- Capitalization of `NotAfter` fixed in DNS TXT response. (#1127)
- Don't log invalid certificates. It is untrusted data and can cause a large
volume of logs. (#1116)
## [1.8.2] - 2024-01-08
### Fixed
- Fix multiple routines when listen.port is zero. This was a regression
introduced in v1.6.0. (#1057)
### Changed
- Small dependency update for Noise. (#1038)
## [1.8.1] - 2023-12-19
### Security
- Update `golang.org/x/crypto`, which includes a fix for CVE-2023-48795. (#1048)
### Fixed
- Fix a deadlock introduced in v1.8.0 that could occur during handshakes. (#1044)
- Fix mobile builds. (#1035)
## [1.8.0] - 2023-12-06
### Deprecated
- The next minor release of Nebula, 1.9.0, will require at least Windows 10 or
Windows Server 2016. This is because support for earlier versions was removed
in Go 1.21. See https://go.dev/doc/go1.21#windows
### Added
- Linux: Notify systemd of service readiness. This should resolve timing issues
with services that depend on Nebula being active. For an example of how to
enable this, see: `examples/service_scripts/nebula.service`. (#929)
- Windows: Use Registered IO (RIO) when possible. Testing on a Windows 11
machine shows ~50x improvement in throughput. (#905)
- NetBSD, OpenBSD: Added rudimentary support. (#916, #812)
- FreeBSD: Add support for naming tun devices. (#903)
### Changed
- `pki.disconnect_invalid` will now default to true. This means that once a
certificate expires, the tunnel will be disconnected. If you use SIGHUP to
reload certificates without restarting Nebula, you should ensure all of your
clients are on 1.7.0 or newer before you enable this feature. (#859)
- Limit how often a busy tunnel can requery the lighthouse. The new config
option `timers.requery_wait_duration` defaults to `60s`. (#940)
- The internal structures for hostmaps were refactored to reduce memory usage
and the potential for subtle bugs. (#843, #938, #953, #954, #955)
- Lots of dependency updates.
### Fixed
- Windows: Retry wintun device creation if it fails the first time. (#985)
- Fix issues with firewall reject packets that could cause panics. (#957)
- Fix relay migration during re-handshakes. (#964)
- Various other refactors and fixes. (#935, #952, #972, #961, #996, #1002,
#987, #1004, #1030, #1032, ...)
## [1.7.2] - 2023-06-01
### Fixed
- Fix a freeze during config reload if the `static_host_map` config was changed. (#886)
## [1.7.1] - 2023-05-18
### Fixed
- Fix IPv4 addresses returned by `static_host_map` DNS lookup queries being
treated as IPv6 addresses. (#877)
## [1.7.0] - 2023-05-17
### Added
- `nebula-cert ca` now supports encrypting the CA's private key with a
passphrase. Pass `-encrypt` in order to be prompted for a passphrase.
Encryption is performed using AES-256-GCM and Argon2id for KDF. KDF
parameters default to RFC recommendations, but can be overridden via CLI
flags `-argon-memory`, `-argon-parallelism`, and `-argon-iterations`. (#386)
- Support for curve P256 and BoringCrypto has been added. See README section
"Curve P256 and BoringCrypto" for more details. (#865, #861, #769, #856, #803)
- New firewall rule `local_cidr`. This could be used to filter destinations
when using `unsafe_routes`. (#507)
- Add `unsafe_route` option `install`. This controls whether the route is
installed in the systems routing table. (#831)
- Add `tun.use_system_route_table` option. Set to true to manage unsafe routes
directly on the system route table with gateway routes instead of in Nebula
configuration files. This is only supported on Linux. (#839)
- The metric `certificate.ttl_seconds` is now exposed via stats. (#782)
- Add `punchy.respond_delay` option. This allows you to change the delay
before attempting punchy.respond. Default is 5 seconds. (#721)
- Added SSH commands to allow the capture of a mutex profile. (#737)
- You can now set `lighthouse.calculated_remotes` to make it possible to do
handshakes without a lighthouse in certain configurations. (#759)
- The firewall can be configured to send REJECT replies instead of the default
DROP behavior. (#738)
- For macOS, an example launchd configuration file is now provided. (#762)
### Changed
- Lighthouses and other `static_host_map` entries that use DNS names will now
be automatically refreshed to detect when the IP address changes. (#796)
- Lighthouses send ACK replies back to clients so that they do not fall into
connection testing as often by clients. (#851, #408)
- Allow the `listen.host` option to contain a hostname. (#825)
- When Nebula switches to a new certificate (such as via SIGHUP), we now
rehandshake with all existing tunnels. This allows firewall groups to be
updated and `pki.disconnect_invalid` to know about the new certificate
expiration time. (#838, #857, #842, #840, #835, #828, #820, #807)
### Fixed
- Always disconnect blocklisted hosts, even if `pki.disconnect_invalid` is
not set. (#858)
- Dependencies updated and go1.20 required. (#780, #824, #855, #854)
- Fix possible race condition with relays. (#827)
- FreeBSD: Fix connection to the localhost's own Nebula IP. (#808)
- Normalize and document some common log field values. (#837, #811)
- Fix crash if you set unlucky values for the firewall timeout configuration
options. (#802)
- Make DNS queries case insensitive. (#793)
- Update example systemd configurations to want `nss-lookup`. (#791)
- Errors with SSH commands now go to the SSH tunnel instead of stderr. (#757)
- Fix a hang when shutting down Android. (#772)
## [1.6.1] - 2022-09-26
### Fixed
- Refuse to process underlay packets received from overlay IPs. This prevents
confusion on hosts that have unsafe routes configured. (#741)
- The ssh `reload` command did not work on Windows, since it relied on sending
a SIGHUP signal internally. This has been fixed. (#725)
- A regression in v1.5.2 that broke unsafe routes on Mobile clients has been
fixed. (#729)
## [1.6.0] - 2022-06-30
### Added
- Experimental: nebula clients can be configured to act as relays for other nebula clients.
Primarily useful when stubborn NATs make a direct tunnel impossible. (#678)
- Configuration option to report manually specified `ip:port`s to lighthouses. (#650)
- Windows arm64 build. (#638)
- `punchy` and most `lighthouse` config options now support hot reloading. (#649)
### Changed
- Build against go 1.18. (#656)
- Promoted `routines` config from experimental to supported feature. (#702)
- Dependencies updated. (#664)
### Fixed
- Packets destined for the same host that sent it will be returned on MacOS.
This matches the default behavior of other operating systems. (#501)
- `unsafe_route` configuration will no longer crash on Windows. (#648)
- A few panics that were introduced in 1.5.x. (#657, #658, #675)
### Security
- You can set `listen.send_recv_error` to control the conditions in which
`recv_error` messages are sent. Sending these messages can expose the fact
that Nebula is running on a host, but it speeds up re-handshaking. (#670)
### Removed
- `x509` config stanza support has been removed. (#685)
## [1.5.2] - 2021-12-14
### Added
- Warn when a non lighthouse node does not have lighthouse hosts configured. (#587)
### Changed
- No longer fatals if expired CA certificates are present in `pki.ca`, as long as 1 valid CA is present. (#599)
- `nebula-cert` will now enforce ipv4 addresses. (#604)
- Warn on macOS if an unsafe route cannot be created due to a collision with an
existing route. (#610)
- Warn if you set a route MTU on platforms where we don't support it. (#611)
### Fixed
- Rare race condition when tearing down a tunnel due to `recv_error` and sending packets on another thread. (#590)
- Bug in `routes` and `unsafe_routes` handling that was introduced in 1.5.0. (#595)
- `-test` mode no longer results in a crash. (#602)
### Removed
- `x509.ca` config alias for `pki.ca`. (#604)
### Security
- Upgraded `golang.org/x/crypto` to address an issue which allowed unauthenticated clients to cause a panic in SSH
servers. (#603)
## 1.5.1 - 2021-12-13
(This release was skipped due to discovering #610 and #611 after the tag was
created.)
## [1.5.0] - 2021-11-11
### Added
- SSH `print-cert` has a new `-raw` flag to get the PEM representation of a certificate. (#483)
- New build architecture: Linux `riscv64`. (#542)
- New experimental config option `remote_allow_ranges`. (#540)
- New config option `pki.disconnect_invalid` that will tear down tunnels when they become invalid (through expiry or
removal of root trust). Default is `false`. Note, this will not currently recognize if a remote has changed
certificates since the last handshake. (#370)
- New config option `unsafe_routes.<route>.metric` will set a metric for a specific unsafe route. It's useful if you have
more than one identical route and want to prefer one against the other. (#353)
### Changed
- Build against go 1.17. (#553)
- Build with `CGO_ENABLED=0` set, to create more portable binaries. This could
have an effect on DNS resolution if you rely on anything non-standard. (#421)
- Windows now uses the [wintun](https://www.wintun.net/) driver which does not require installation. This driver
is a large improvement over the TAP driver that was used in previous versions. If you had a previous version
of `nebula` running, you will want to disable the tap driver in Control Panel, or uninstall the `tap0901` driver
before running this version. (#289)
- Darwin binaries are now universal (works on both amd64 and arm64), signed, and shipped in a notarized zip file.
`nebula-darwin.zip` will be the only darwin release artifact. (#571)
- Darwin uses syscalls and AF_ROUTE to configure the routing table, instead of
using `/sbin/route`. Setting `tun.dev` is now allowed on Darwin as well, it
must be in the format `utun[0-9]+` or it will be ignored. (#163)
### Deprecated
- The `preferred_ranges` option has been supported as a replacement for
`local_range` since v1.0.0. It has now been documented and `local_range`
has been officially deprecated. (#541)
### Fixed
- Valid recv_error packets were incorrectly marked as "spoofing" and ignored. (#482)
- SSH server handles single `exec` requests correctly. (#483)
- Signing a certificate with `nebula-cert sign` now verifies that the supplied
ca-key matches the ca-crt. (#503)
- If `preferred_ranges` (or the deprecated `local_range`) is configured, we
will immediately switch to a preferred remote address after the reception of
a handshake packet (instead of waiting until 1,000 packets have been sent).
(#532)
- A race condition when `punchy.respond` is enabled and ensures the correct
vpn ip is sent a punch back response in highly queried node. (#566)
- Fix a rare crash during handshake due to a race condition. (#535)
## [1.4.0] - 2021-05-11
### Added
- Ability to output qr code images in `print`, `ca`, and `sign` modes for `nebula-cert`.
This is useful when configuring mobile clients. (#297)
- Experimental: Nebula can now do work on more than 2 cpu cores in send and receive paths via
the new `routines` config option. (#382, #391, #395)
- ICMP ping requests can be responded to when the `tun.disabled` is `true`.
This is useful so that you can "ping" a lighthouse running in this mode. (#342)
- Run smoke tests via `make smoke-docker`. (#287)
- More reported stats, udp memory use on linux, build version (when using Prometheus), firewall,
handshake, and cached packet stats. (#390, #405, #450, #453)
- IPv6 support for the underlay network. (#369)
- End to end testing, run with `make e2e`. (#425, #427, #428)
### Changed
- Darwin will now log stdout/stderr to a file when using `-service` mode. (#303)
- Example systemd unit file now better arranged startup order when using `sshd`
and other fixes. (#317, #412, #438)
- Reduced memory utilization/garbage collection. (#320, #323, #340)
- Reduced CPU utilization. (#329)
- Build against go 1.16. (#381)
- Refactored handshakes to improve performance and correctness. (#401, #402, #404, #416, #451)
- Improved roaming support for mobile clients. (#394, #457)
- Lighthouse performance and correctness improvements. (#406, #418, #429, #433, #437, #442, #449)
- Better ordered startup to enable `sshd`, `stats`, and `dns` subsystems to listen on
the nebula interface. (#375)
### Fixed
- No longer report handshake packets as `lost` in stats. (#331)
- Error handling in the `cert` package. (#339, #373)
- Orphaned pending hostmap entries are cleaned up. (#344)
- Most known data races are now resolved. (#396, #400, #424)
- Refuse to run a lighthouse on an ephemeral port. (#399)
- Removed the global references. (#423, #426, #446)
- Reloading via ssh command avoids a panic. (#447)
- Shutdown is now performed in a cleaner way. (#448)
- Logs will now find their way to Windows event viewer when running under `-service` mode
in Windows. (#443)
## [1.3.0] - 2020-09-22
### Added
- You can emit statistics about non-message packets by setting the option
`stats.message_metrics`. You can similarly emit detailed statistics about
lighthouse packets by setting the option `stats.lighthouse_metrics`. See
the example config for more details. (#230)
- We now support freebsd/amd64. This is experimental, please give us feedback.
(#103)
- We now release a binary for `linux/mips-softfloat` which has also been
stripped to reduce filesize and hopefully have a better chance on running on
small mips devices. (#231)
- You can set `tun.disabled` to true to run a standalone lighthouse without a
tun device (and thus, without root). (#269)
- You can set `logging.disable_timestamp` to remove timestamps from log lines,
which is useful when output is redirected to a logging system that already
adds timestamps. (#288)
### Changed
- Handshakes should now trigger faster, as we try to be proactive with sending
them instead of waiting for the next timer tick in most cases. (#246, #265)
- Previously, we would drop the conntrack table whenever firewall rules were
changed during a SIGHUP. Now, we will maintain the table and just validate
that an entry still matches with the new rule set. (#233)
- Debug logs for firewall drops now include the reason. (#220, #239)
- Logs for handshakes now include the fingerprint of the remote host. (#262)
- Config item `pki.blacklist` is now `pki.blocklist`. (#272)
- Better support for older Linux kernels. We now only set `SO_REUSEPORT` if
`tun.routines` is greater than 1 (default is 1). We also only use the
`recvmmsg` syscall if `listen.batch` is greater than 1 (default is 64).
(#275)
- It is possible to run Nebula as a library inside of another process now.
Note that this is still experimental and the internal APIs around this might
change in minor version releases. (#279)
### Deprecated
- `pki.blacklist` is deprecated in favor of `pki.blocklist` with the same
functionality. Existing configs will continue to load for this release to
allow for migrations. (#272)
### Fixed
- `advmss` is now set correctly for each route table entry when `tun.routes`
is configured to have some routes with higher MTU. (#245)
- Packets that arrive on the tun device with an unroutable destination IP are
now dropped correctly, instead of wasting time making queries to the
lighthouses for IP `0.0.0.0` (#267)
## [1.2.0] - 2020-04-08
### Added
- Add `logging.timestamp_format` config option. The primary purpose of this
change is to allow logging timestamps with millisecond precision. (#187)
- Support `unsafe_routes` on Windows. (#184)
- Add `lighthouse.remote_allow_list` to filter which subnets we will use to
handshake with other hosts. See the example config for more details. (#217)
- Add `lighthouse.local_allow_list` to filter which local IP addresses and/or
interfaces we advertise to the lighthouses. See the example config for more
details. (#217)
- Wireshark dissector plugin. Add this file in `dist/wireshark` to your
Wireshark plugins folder to see Nebula packet headers decoded. (#216)
- systemd unit for Arch, so it can be built entirely from this repo. (#216)
### Changed
- Added a delay to punching via lighthouse signal to deal with race conditions
in some linux conntrack implementations. (#210)
See deprecated, this also adds a new `punchy.delay` option that defaults to `1s`.
- Validate all `lighthouse.hosts` and `static_host_map` VPN IPs are in the
subnet defined in our cert. Exit with a fatal error if they are not in our
subnet, as this is an invalid configuration (we will not have the proper
routes set up to communicate with these hosts). (#170)
- Use absolute paths to system binaries on macOS and Windows. (#191)
- Add configuration options for `handshakes`. This includes options to tweak
`try_interval`, `retries` and `wait_rotation`. See example config for
descriptions. (#179)
- Allow `-config` file to not end in `.yaml` or `yml`. Useful when using
`-test` and automated tools like Ansible that create temporary files without
suffixes. (#189)
- The config test mode, `-test`, is now more thorough and catches more parsing
issues. (#177)
- Various documentation and example fixes. (#196)
- Improved log messages. (#181, #200)
- Dependencies updated. (#188)
### Deprecated
- `punchy`, `punch_back` configuration options have been collapsed under the
now top level `punchy` config directive. (#210)
`punchy.punch` - This is the old `punchy` option. Should we perform NAT hole
punching (default false)?
`punchy.respond` - This is the old `punch_back` option. Should we respond to
hole punching by hole punching back (default false)?
### Fixed
- Reduce memory allocations when not using `unsafe_routes`. (#198)
- Ignore packets from self to self. (#192)
- MTU fixed for `unsafe_routes`. (#209)
## [1.1.0] - 2020-01-17
### Added
- For macOS and Windows, build a special version of the binary that can install
and manage its own service configuration. You can use this with `nebula
-service`. If you are building from source, use `make service` to build this feature.
- Support for `mips`, `mips64`, `386` and `ppc64le` processors on Linux.
- You can now configure the DNS listen host and port with `lighthouse.dns.host`
and `lighthouse.dns.port`.
- Subnet and routing support. You can now add a `unsafe_routes` section to your
config to allow hosts to act as gateways to other subnets. Read the example
config for more details. This is supported on Linux and macOS.
### Changed
- Certificates now have more verifications performed, including making sure
the certificate lifespan does not exceed the lifespan of the root CA. This
could cause issues if you have signed certificates with expirations beyond
the expiration of your CA, and you will need to reissue your certificates.
- If lighthouse interval is set to `0`, never update the lighthouse (mobile
optimization).
- Various documentation and example fixes.
- Improved error messages.
- Dependencies updated.
### Fixed
- If you have a firewall rule with `group: ["one-group"]`, this will
now be accepted, with a warning to use `group: "one-group"` instead.
- The `listen.host` configuration option was previously ignored (the bind host
was always 0.0.0.0). This option will now be honored.
- The `ca_sha` and `ca_name` firewall rule options should now work correctly.
## [1.0.0] - 2019-11-19
### Added
- Initial public release.
[Unreleased]: https://github.com/slackhq/nebula/compare/v1.10.3...HEAD
[1.10.3]: https://github.com/slackhq/nebula/releases/tag/v1.10.3
[1.10.2]: https://github.com/slackhq/nebula/releases/tag/v1.10.2
[1.10.1]: https://github.com/slackhq/nebula/releases/tag/v1.10.1
[1.10.0]: https://github.com/slackhq/nebula/releases/tag/v1.10.0
[1.9.7]: https://github.com/slackhq/nebula/releases/tag/v1.9.7
[1.9.6]: https://github.com/slackhq/nebula/releases/tag/v1.9.6
[1.9.5]: https://github.com/slackhq/nebula/releases/tag/v1.9.5
[1.9.4]: https://github.com/slackhq/nebula/releases/tag/v1.9.4
[1.9.3]: https://github.com/slackhq/nebula/releases/tag/v1.9.3
[1.9.2]: https://github.com/slackhq/nebula/releases/tag/v1.9.2
[1.9.1]: https://github.com/slackhq/nebula/releases/tag/v1.9.1
[1.9.0]: https://github.com/slackhq/nebula/releases/tag/v1.9.0
[1.8.2]: https://github.com/slackhq/nebula/releases/tag/v1.8.2
[1.8.1]: https://github.com/slackhq/nebula/releases/tag/v1.8.1
[1.8.0]: https://github.com/slackhq/nebula/releases/tag/v1.8.0
[1.7.2]: https://github.com/slackhq/nebula/releases/tag/v1.7.2
[1.7.1]: https://github.com/slackhq/nebula/releases/tag/v1.7.1
[1.7.0]: https://github.com/slackhq/nebula/releases/tag/v1.7.0
[1.6.1]: https://github.com/slackhq/nebula/releases/tag/v1.6.1
[1.6.0]: https://github.com/slackhq/nebula/releases/tag/v1.6.0
[1.5.2]: https://github.com/slackhq/nebula/releases/tag/v1.5.2
[1.5.0]: https://github.com/slackhq/nebula/releases/tag/v1.5.0
[1.4.0]: https://github.com/slackhq/nebula/releases/tag/v1.4.0
[1.3.0]: https://github.com/slackhq/nebula/releases/tag/v1.3.0
[1.2.0]: https://github.com/slackhq/nebula/releases/tag/v1.2.0
[1.1.0]: https://github.com/slackhq/nebula/releases/tag/v1.1.0
[1.0.0]: https://github.com/slackhq/nebula/releases/tag/v1.0.0
================================================
FILE: CODEOWNERS
================================================
#ECCN:Open Source
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018-2019 Slack Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: LOGGING.md
================================================
### Logging conventions
A log message (the string/format passed to `Info`, `Error`, `Debug` etc, as well as their `Sprintf` counterparts) should
be a descriptive message about the event and may contain specific identifying characteristics. Regardless of the
level of detail in the message identifying characteristics should always be included via `WithField`, `WithFields` or
`WithError`
If an error is being logged use `l.WithError(err)` so that there is better discoverability about the event as well
as the specific error condition.
#### Common fields
- `cert` - a `cert.NebulaCertificate` object, do not `.String()` this manually, `logrus` will marshal objects properly
for the formatter it is using.
- `fingerprint` - a single `NebeulaCertificate` hex encoded fingerprint
- `fingerprints` - an array of `NebulaCertificate` hex encoded fingerprints
- `fwPacket` - a FirewallPacket object
- `handshake` - an object containing:
- `stage` - the current stage counter
- `style` - noise handshake style `ix_psk0`, `xx`, etc
- `header` - a nebula header object
- `udpAddr` - a `net.UDPAddr` object
- `udpIp` - a udp ip address
- `vpnIp` - vpn ip of the host (remote or local)
- `relay` - the vpnIp of the relay host that is or should be handling the relay packet
- `relayFrom` - The vpnIp of the initial sender of the relayed packet
- `relayTo` - The vpnIp of the final destination of a relayed packet
#### Example:
```
l.WithError(err).
WithField("vpnIp", IntIp(hostinfo.hostId)).
WithField("udpAddr", addr).
WithField("handshake", m{"stage": 1, "style": "ix"}).
Info("Invalid certificate from host")
```
================================================
FILE: Makefile
================================================
NEBULA_CMD_PATH = "./cmd/nebula"
CGO_ENABLED = 0
export CGO_ENABLED
# Set up OS specific bits
ifeq ($(OS),Windows_NT)
NEBULA_CMD_SUFFIX = .exe
NULL_FILE = nul
# RIO on windows does pointer stuff that makes go vet angry
VET_FLAGS = -unsafeptr=false
else
NEBULA_CMD_SUFFIX =
NULL_FILE = /dev/null
endif
# Only defined the build number if we haven't already
ifndef BUILD_NUMBER
ifeq ($(shell git describe --exact-match 2>$(NULL_FILE)),)
BUILD_NUMBER = $(shell git describe --abbrev=0 --match "v*" | cut -dv -f2)-$(shell git branch --show-current)-$(shell git describe --long --dirty | cut -d- -f2-)
else
BUILD_NUMBER = $(shell git describe --exact-match --dirty | cut -dv -f2)
endif
endif
DOCKER_IMAGE_REPO ?= nebulaoss/nebula
DOCKER_IMAGE_TAG ?= latest
LDFLAGS = -X main.Build=$(BUILD_NUMBER)
ALL_LINUX = linux-amd64 \
linux-386 \
linux-ppc64le \
linux-arm-5 \
linux-arm-6 \
linux-arm-7 \
linux-arm64 \
linux-mips \
linux-mipsle \
linux-mips64 \
linux-mips64le \
linux-mips-softfloat \
linux-riscv64 \
linux-loong64
ALL_FREEBSD = freebsd-amd64 \
freebsd-arm64
ALL_OPENBSD = openbsd-amd64 \
openbsd-arm64
ALL_NETBSD = netbsd-amd64 \
netbsd-arm64
ALL = $(ALL_LINUX) \
$(ALL_FREEBSD) \
$(ALL_OPENBSD) \
$(ALL_NETBSD) \
darwin-amd64 \
darwin-arm64 \
windows-amd64 \
windows-arm64
e2e:
$(TEST_ENV) go test -tags=e2e_testing -count=1 $(TEST_FLAGS) ./e2e
e2ev: TEST_FLAGS += -v
e2ev: e2e
e2evv: TEST_ENV += TEST_LOGS=1
e2evv: e2ev
e2evvv: TEST_ENV += TEST_LOGS=2
e2evvv: e2ev
e2evvvv: TEST_ENV += TEST_LOGS=3
e2evvvv: e2ev
e2e-bench: TEST_FLAGS = -bench=. -benchmem -run=^$
e2e-bench: e2e
DOCKER_BIN = build/linux-amd64/nebula build/linux-amd64/nebula-cert
all: $(ALL:%=build/%/nebula) $(ALL:%=build/%/nebula-cert)
docker: docker/linux-$(shell go env GOARCH)
release: $(ALL:%=build/nebula-%.tar.gz)
release-linux: $(ALL_LINUX:%=build/nebula-%.tar.gz)
release-freebsd: $(ALL_FREEBSD:%=build/nebula-%.tar.gz)
release-openbsd: $(ALL_OPENBSD:%=build/nebula-%.tar.gz)
release-netbsd: $(ALL_NETBSD:%=build/nebula-%.tar.gz)
release-boringcrypto: build/nebula-linux-$(shell go env GOARCH)-boringcrypto.tar.gz
BUILD_ARGS += -trimpath
bin-windows: build/windows-amd64/nebula.exe build/windows-amd64/nebula-cert.exe
mv $? .
bin-windows-arm64: build/windows-arm64/nebula.exe build/windows-arm64/nebula-cert.exe
mv $? .
bin-darwin: build/darwin-amd64/nebula build/darwin-amd64/nebula-cert
mv $? .
bin-freebsd: build/freebsd-amd64/nebula build/freebsd-amd64/nebula-cert
mv $? .
bin-freebsd-arm64: build/freebsd-arm64/nebula build/freebsd-arm64/nebula-cert
mv $? .
bin-boringcrypto: build/linux-$(shell go env GOARCH)-boringcrypto/nebula build/linux-$(shell go env GOARCH)-boringcrypto/nebula-cert
mv $? .
bin-pkcs11: BUILD_ARGS += -tags pkcs11
bin-pkcs11: CGO_ENABLED = 1
bin-pkcs11: bin
bin:
go build $(BUILD_ARGS) -ldflags "$(LDFLAGS)" -o ./nebula${NEBULA_CMD_SUFFIX} ${NEBULA_CMD_PATH}
go build $(BUILD_ARGS) -ldflags "$(LDFLAGS)" -o ./nebula-cert${NEBULA_CMD_SUFFIX} ./cmd/nebula-cert
install:
go install $(BUILD_ARGS) -ldflags "$(LDFLAGS)" ${NEBULA_CMD_PATH}
go install $(BUILD_ARGS) -ldflags "$(LDFLAGS)" ./cmd/nebula-cert
build/linux-arm-%: GOENV += GOARM=$(word 3, $(subst -, ,$*))
build/linux-mips-%: GOENV += GOMIPS=$(word 3, $(subst -, ,$*))
# Build an extra small binary for mips-softfloat
build/linux-mips-softfloat/%: LDFLAGS += -s -w
# boringcrypto
build/linux-amd64-boringcrypto/%: GOENV += GOEXPERIMENT=boringcrypto CGO_ENABLED=1
build/linux-arm64-boringcrypto/%: GOENV += GOEXPERIMENT=boringcrypto CGO_ENABLED=1
build/linux-amd64-boringcrypto/%: LDFLAGS += -checklinkname=0
build/linux-arm64-boringcrypto/%: LDFLAGS += -checklinkname=0
build/%/nebula: .FORCE
GOOS=$(firstword $(subst -, , $*)) \
GOARCH=$(word 2, $(subst -, ,$*)) $(GOENV) \
go build $(BUILD_ARGS) -o $@ -ldflags "$(LDFLAGS)" ${NEBULA_CMD_PATH}
build/%/nebula-cert: .FORCE
GOOS=$(firstword $(subst -, , $*)) \
GOARCH=$(word 2, $(subst -, ,$*)) $(GOENV) \
go build $(BUILD_ARGS) -o $@ -ldflags "$(LDFLAGS)" ./cmd/nebula-cert
build/%/nebula.exe: build/%/nebula
mv $< $@
build/%/nebula-cert.exe: build/%/nebula-cert
mv $< $@
build/nebula-%.tar.gz: build/%/nebula build/%/nebula-cert
tar -zcv -C build/$* -f $@ nebula nebula-cert
build/nebula-%.zip: build/%/nebula.exe build/%/nebula-cert.exe
cd build/$* && zip ../nebula-$*.zip nebula.exe nebula-cert.exe
docker/%: build/%/nebula build/%/nebula-cert
docker build . $(DOCKER_BUILD_ARGS) -f docker/Dockerfile --platform "$(subst -,/,$*)" --tag "${DOCKER_IMAGE_REPO}:${DOCKER_IMAGE_TAG}" --tag "${DOCKER_IMAGE_REPO}:$(BUILD_NUMBER)"
vet:
go vet $(VET_FLAGS) -v ./...
test:
go test -v ./...
test-boringcrypto:
GOEXPERIMENT=boringcrypto CGO_ENABLED=1 go test -ldflags "-checklinkname=0" -v ./...
test-pkcs11:
CGO_ENABLED=1 go test -v -tags pkcs11 ./...
test-cov-html:
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
build-test-mobile:
GOARCH=amd64 GOOS=ios go build $(shell go list ./... | grep -v '/cmd/\|/examples/')
GOARCH=arm64 GOOS=ios go build $(shell go list ./... | grep -v '/cmd/\|/examples/')
GOARCH=amd64 GOOS=android go build $(shell go list ./... | grep -v '/cmd/\|/examples/')
GOARCH=arm64 GOOS=android go build $(shell go list ./... | grep -v '/cmd/\|/examples/')
bench:
go test -bench=.
bench-cpu:
go test -bench=. -benchtime=5s -cpuprofile=cpu.pprof
go tool pprof go-audit.test cpu.pprof
bench-cpu-long:
go test -bench=. -benchtime=60s -cpuprofile=cpu.pprof
go tool pprof go-audit.test cpu.pprof
proto: nebula.pb.go cert/cert_v1.pb.go
nebula.pb.go: nebula.proto .FORCE
go build github.com/gogo/protobuf/protoc-gen-gogofaster
PATH="$(CURDIR):$(PATH)" protoc --gogofaster_out=paths=source_relative:. $<
rm protoc-gen-gogofaster
cert/cert.pb.go: cert/cert.proto .FORCE
$(MAKE) -C cert cert.pb.go
service:
@echo > $(NULL_FILE)
$(eval NEBULA_CMD_PATH := "./cmd/nebula-service")
ifeq ($(words $(MAKECMDGOALS)),1)
@$(MAKE) service ${.DEFAULT_GOAL} --no-print-directory
endif
bin-docker: bin build/linux-amd64/nebula build/linux-amd64/nebula-cert
smoke-docker: bin-docker
cd .github/workflows/smoke/ && ./build.sh
cd .github/workflows/smoke/ && ./smoke.sh
cd .github/workflows/smoke/ && NAME="smoke-p256" CURVE="P256" ./build.sh
cd .github/workflows/smoke/ && NAME="smoke-p256" ./smoke.sh
smoke-relay-docker: bin-docker
cd .github/workflows/smoke/ && ./build-relay.sh
cd .github/workflows/smoke/ && ./smoke-relay.sh
smoke-docker-race: BUILD_ARGS = -race
smoke-docker-race: CGO_ENABLED = 1
smoke-docker-race: smoke-docker
smoke-vagrant/%: bin-docker build/%/nebula
cd .github/workflows/smoke/ && ./build.sh $*
cd .github/workflows/smoke/ && ./smoke-vagrant.sh $*
.FORCE:
.PHONY: bench bench-cpu bench-cpu-long bin build-test-mobile e2e e2ev e2evv e2evvv e2evvvv proto release service smoke-docker smoke-docker-race test test-cov-html smoke-vagrant/%
.DEFAULT_GOAL := bin
================================================
FILE: README.md
================================================
## What is Nebula?
Nebula is a scalable overlay networking tool with a focus on performance, simplicity and security.
It lets you seamlessly connect computers anywhere in the world. Nebula is portable, and runs on Linux, OSX, Windows, iOS, and Android.
It can be used to connect a small number of computers, but is also able to connect tens of thousands of computers.
Nebula incorporates a number of existing concepts like encryption, security groups, certificates,
and tunneling.
What makes Nebula different to existing offerings is that it brings all of these ideas together,
resulting in a sum that is greater than its individual parts.
Further documentation can be found [here](https://nebula.defined.net/docs/).
You can read more about Nebula [here](https://medium.com/p/884110a5579).
You can also join the NebulaOSS Slack group [here](https://join.slack.com/t/nebulaoss/shared_invite/zt-39pk4xopc-CUKlGcb5Z39dQ0cK1v7ehA).
## Supported Platforms
#### Desktop and Server
Check the [releases](https://github.com/slackhq/nebula/releases/latest) page for downloads or see the [Distribution Packages](https://github.com/slackhq/nebula#distribution-packages) section.
- Linux - 64 and 32 bit, arm, and others
- Windows
- MacOS
- Freebsd
#### Distribution Packages
- [Arch Linux](https://archlinux.org/packages/extra/x86_64/nebula/)
```sh
sudo pacman -S nebula
```
- [Fedora Linux](https://src.fedoraproject.org/rpms/nebula)
```sh
sudo dnf install nebula
```
- [Debian Linux](https://packages.debian.org/source/stable/nebula)
```sh
sudo apt install nebula
```
- [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=nebula)
```sh
sudo apk add nebula
```
- [macOS Homebrew](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/n/nebula.rb)
```sh
brew install nebula
```
- [Docker](https://hub.docker.com/r/nebulaoss/nebula)
```sh
docker pull nebulaoss/nebula
```
#### Mobile
- [iOS](https://apps.apple.com/us/app/mobile-nebula/id1509587936?itsct=apps_box&itscg=30200)
- [Android](https://play.google.com/store/apps/details?id=net.defined.mobile_nebula&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1)
## Technical Overview
Nebula is a mutually authenticated peer-to-peer software-defined network based on the [Noise Protocol Framework](https://noiseprotocol.org/).
Nebula uses certificates to assert a node's IP address, name, and membership within user-defined groups.
Nebula's user-defined groups allow for provider agnostic traffic filtering between nodes.
Discovery nodes (aka lighthouses) allow individual peers to find each other and optionally use UDP hole punching to establish connections from behind most firewalls or NATs.
Users can move data between nodes in any number of cloud service providers, datacenters, and endpoints, without needing to maintain a particular addressing scheme.
Nebula uses Elliptic-curve Diffie-Hellman (`ECDH`) key exchange and `AES-256-GCM` in its default configuration.
Nebula was created to provide a mechanism for groups of hosts to communicate securely, even across the internet, while enabling expressive firewall definitions similar in style to cloud security groups.
## Getting started (quickly)
To set up a Nebula network, you'll need:
#### 1. The [Nebula binaries](https://github.com/slackhq/nebula/releases) or [Distribution Packages](https://github.com/slackhq/nebula#distribution-packages) for your specific platform. Specifically you'll need `nebula-cert` and the specific nebula binary for each platform you use.
#### 2. (Optional, but you really should..) At least one discovery node with a routable IP address, which we call a lighthouse.
Nebula lighthouses allow nodes to find each other, anywhere in the world. A lighthouse is the only node in a Nebula network whose IP should not change. Running a lighthouse requires very few compute resources, and you can easily use the least expensive option from a cloud hosting provider. If you're not sure which provider to use, a number of us have used $6/mo [DigitalOcean](https://digitalocean.com) droplets as lighthouses.
Once you have launched an instance, ensure that Nebula udp traffic (default port udp/4242) can reach it over the internet.
#### 3. A Nebula certificate authority, which will be the root of trust for a particular Nebula network.
```sh
./nebula-cert ca -name "Myorganization, Inc"
```
This will create files named `ca.key` and `ca.cert` in the current directory. The `ca.key` file is the most sensitive file you'll create, because it is the key used to sign the certificates for individual nebula nodes/hosts. Please store this file somewhere safe, preferably with strong encryption.
**Be aware!** By default, certificate authorities have a 1-year lifetime before expiration. See [this guide](https://nebula.defined.net/docs/guides/rotating-certificate-authority/) for details on rotating a CA.
#### 4. Nebula host keys and certificates generated from that certificate authority
This assumes you have four nodes, named lighthouse1, laptop, server1, host3. You can name the nodes any way you'd like, including FQDN. You'll also need to choose IP addresses and the associated subnet. In this example, we are creating a nebula network that will use 192.168.100.x/24 as its network range. This example also demonstrates nebula groups, which can later be used to define traffic rules in a nebula network.
```sh
./nebula-cert sign -name "lighthouse1" -ip "192.168.100.1/24"
./nebula-cert sign -name "laptop" -ip "192.168.100.2/24" -groups "laptop,home,ssh"
./nebula-cert sign -name "server1" -ip "192.168.100.9/24" -groups "servers"
./nebula-cert sign -name "host3" -ip "192.168.100.10/24"
```
By default, host certificates will expire 1 second before the CA expires. Use the `-duration` flag to specify a shorter lifetime.
#### 5. Configuration files for each host
Download a copy of the nebula [example configuration](https://github.com/slackhq/nebula/blob/master/examples/config.yml).
* On the lighthouse node, you'll need to ensure `am_lighthouse: true` is set.
* On the individual hosts, ensure the lighthouse is defined properly in the `static_host_map` section, and is added to the lighthouse `hosts` section.
#### 6. Copy nebula credentials, configuration, and binaries to each host
For each host, copy the nebula binary to the host, along with `config.yml` from step 5, and the files `ca.crt`, `{host}.crt`, and `{host}.key` from step 4.
**DO NOT COPY `ca.key` TO INDIVIDUAL NODES.**
#### 7. Run nebula on each host
```sh
./nebula -config /path/to/config.yml
```
For more detailed instructions, [find the full documentation here](https://nebula.defined.net/docs/).
## Building Nebula from source
Make sure you have [go](https://go.dev/doc/install) installed and clone this repo. Change to the nebula directory.
To build nebula for all platforms:
`make all`
To build nebula for a specific platform (ex, Windows):
`make bin-windows`
See the [Makefile](Makefile) for more details on build targets
## Curve P256 and BoringCrypto
The default curve used for cryptographic handshakes and signatures is Curve25519. This is the recommended setting for most users. If your deployment has certain compliance requirements, you have the option of creating your CA using `nebula-cert ca -curve P256` to use NIST Curve P256. The CA will then sign certificates using ECDSA P256, and any hosts using these certificates will use P256 for ECDH handshakes.
In addition, Nebula can be built using the [BoringCrypto GOEXPERIMENT](https://github.com/golang/go/blob/go1.20/src/crypto/internal/boring/README.md) by running either of the following make targets:
```sh
make bin-boringcrypto
make release-boringcrypto
```
This is not the recommended default deployment, but may be useful based on your compliance requirements.
## Credits
Nebula was created at Slack Technologies, Inc by Nate Brown and Ryan Huber, with contributions from Oliver Fross, Alan Lam, Wade Simmons, and Lining Wang.
================================================
FILE: SECURITY.md
================================================
Security Policy
===============
Reporting a Vulnerability
-------------------------
If you believe you have found a security vulnerability with Nebula, please let
us know right away. We will investigate all reports and do our best to quickly
fix valid issues.
You can submit your report on [HackerOne](https://hackerone.com/slack) and our
security team will respond as soon as possible.
================================================
FILE: allow_list.go
================================================
package nebula
import (
"fmt"
"net/netip"
"regexp"
"github.com/gaissmai/bart"
"github.com/slackhq/nebula/config"
)
type AllowList struct {
// The values of this cidrTree are `bool`, signifying allow/deny
cidrTree *bart.Table[bool]
}
type RemoteAllowList struct {
AllowList *AllowList
// Inside Range Specific, keys of this tree are inside CIDRs and values
// are *AllowList
insideAllowLists *bart.Table[*AllowList]
}
type LocalAllowList struct {
AllowList *AllowList
// To avoid ambiguity, all rules must be true, or all rules must be false.
nameRules []AllowListNameRule
}
type AllowListNameRule struct {
Name *regexp.Regexp
Allow bool
}
func NewLocalAllowListFromConfig(c *config.C, k string) (*LocalAllowList, error) {
var nameRules []AllowListNameRule
handleKey := func(key string, value any) (bool, error) {
if key == "interfaces" {
var err error
nameRules, err = getAllowListInterfaces(k, value)
if err != nil {
return false, err
}
return true, nil
}
return false, nil
}
al, err := newAllowListFromConfig(c, k, handleKey)
if err != nil {
return nil, err
}
return &LocalAllowList{AllowList: al, nameRules: nameRules}, nil
}
func NewRemoteAllowListFromConfig(c *config.C, k, rangesKey string) (*RemoteAllowList, error) {
al, err := newAllowListFromConfig(c, k, nil)
if err != nil {
return nil, err
}
remoteAllowRanges, err := getRemoteAllowRanges(c, rangesKey)
if err != nil {
return nil, err
}
return &RemoteAllowList{AllowList: al, insideAllowLists: remoteAllowRanges}, nil
}
// If the handleKey func returns true, the rest of the parsing is skipped
// for this key. This allows parsing of special values like `interfaces`.
func newAllowListFromConfig(c *config.C, k string, handleKey func(key string, value any) (bool, error)) (*AllowList, error) {
r := c.Get(k)
if r == nil {
return nil, nil
}
return newAllowList(k, r, handleKey)
}
// If the handleKey func returns true, the rest of the parsing is skipped
// for this key. This allows parsing of special values like `interfaces`.
func newAllowList(k string, raw any, handleKey func(key string, value any) (bool, error)) (*AllowList, error) {
rawMap, ok := raw.(map[string]any)
if !ok {
return nil, fmt.Errorf("config `%s` has invalid type: %T", k, raw)
}
tree := new(bart.Table[bool])
// Keep track of the rules we have added for both ipv4 and ipv6
type allowListRules struct {
firstValue bool
allValuesMatch bool
defaultSet bool
allValues bool
}
rules4 := allowListRules{firstValue: true, allValuesMatch: true, defaultSet: false}
rules6 := allowListRules{firstValue: true, allValuesMatch: true, defaultSet: false}
for rawCIDR, rawValue := range rawMap {
if handleKey != nil {
handled, err := handleKey(rawCIDR, rawValue)
if err != nil {
return nil, err
}
if handled {
continue
}
}
value, ok := config.AsBool(rawValue)
if !ok {
return nil, fmt.Errorf("config `%s` has invalid value (type %T): %v", k, rawValue, rawValue)
}
ipNet, err := netip.ParsePrefix(rawCIDR)
if err != nil {
return nil, fmt.Errorf("config `%s` has invalid CIDR: %s. %w", k, rawCIDR, err)
}
ipNet = netip.PrefixFrom(ipNet.Addr().Unmap(), ipNet.Bits())
tree.Insert(ipNet, value)
maskBits := ipNet.Bits()
var rules *allowListRules
if ipNet.Addr().Is4() {
rules = &rules4
} else {
rules = &rules6
}
if rules.firstValue {
rules.allValues = value
rules.firstValue = false
} else {
if value != rules.allValues {
rules.allValuesMatch = false
}
}
// Check if this is 0.0.0.0/0 or ::/0
if maskBits == 0 {
rules.defaultSet = true
}
}
if !rules4.defaultSet {
if rules4.allValuesMatch {
tree.Insert(netip.PrefixFrom(netip.IPv4Unspecified(), 0), !rules4.allValues)
} else {
return nil, fmt.Errorf("config `%s` contains both true and false rules, but no default set for 0.0.0.0/0", k)
}
}
if !rules6.defaultSet {
if rules6.allValuesMatch {
tree.Insert(netip.PrefixFrom(netip.IPv6Unspecified(), 0), !rules6.allValues)
} else {
return nil, fmt.Errorf("config `%s` contains both true and false rules, but no default set for ::/0", k)
}
}
return &AllowList{cidrTree: tree}, nil
}
func getAllowListInterfaces(k string, v any) ([]AllowListNameRule, error) {
var nameRules []AllowListNameRule
rawRules, ok := v.(map[string]any)
if !ok {
return nil, fmt.Errorf("config `%s.interfaces` is invalid (type %T): %v", k, v, v)
}
firstEntry := true
var allValues bool
for name, rawAllow := range rawRules {
allow, ok := config.AsBool(rawAllow)
if !ok {
return nil, fmt.Errorf("config `%s.interfaces` has invalid value (type %T): %v", k, rawAllow, rawAllow)
}
nameRE, err := regexp.Compile("^" + name + "$")
if err != nil {
return nil, fmt.Errorf("config `%s.interfaces` has invalid key: %s: %v", k, name, err)
}
nameRules = append(nameRules, AllowListNameRule{
Name: nameRE,
Allow: allow,
})
if firstEntry {
allValues = allow
firstEntry = false
} else {
if allow != allValues {
return nil, fmt.Errorf("config `%s.interfaces` values must all be the same true/false value", k)
}
}
}
return nameRules, nil
}
func getRemoteAllowRanges(c *config.C, k string) (*bart.Table[*AllowList], error) {
value := c.Get(k)
if value == nil {
return nil, nil
}
remoteAllowRanges := new(bart.Table[*AllowList])
rawMap, ok := value.(map[string]any)
if !ok {
return nil, fmt.Errorf("config `%s` has invalid type: %T", k, value)
}
for rawCIDR, rawValue := range rawMap {
allowList, err := newAllowList(fmt.Sprintf("%s.%s", k, rawCIDR), rawValue, nil)
if err != nil {
return nil, err
}
ipNet, err := netip.ParsePrefix(rawCIDR)
if err != nil {
return nil, fmt.Errorf("config `%s` has invalid CIDR: %s. %w", k, rawCIDR, err)
}
remoteAllowRanges.Insert(netip.PrefixFrom(ipNet.Addr().Unmap(), ipNet.Bits()), allowList)
}
return remoteAllowRanges, nil
}
func (al *AllowList) Allow(addr netip.Addr) bool {
if al == nil {
return true
}
result, _ := al.cidrTree.Lookup(addr)
return result
}
func (al *LocalAllowList) Allow(udpAddr netip.Addr) bool {
if al == nil {
return true
}
return al.AllowList.Allow(udpAddr)
}
func (al *LocalAllowList) AllowName(name string) bool {
if al == nil || len(al.nameRules) == 0 {
return true
}
for _, rule := range al.nameRules {
if rule.Name.MatchString(name) {
return rule.Allow
}
}
// If no rules match, return the default, which is the inverse of the rules
return !al.nameRules[0].Allow
}
func (al *RemoteAllowList) AllowUnknownVpnAddr(vpnAddr netip.Addr) bool {
if al == nil {
return true
}
return al.AllowList.Allow(vpnAddr)
}
func (al *RemoteAllowList) Allow(vpnAddr netip.Addr, udpAddr netip.Addr) bool {
if !al.getInsideAllowList(vpnAddr).Allow(udpAddr) {
return false
}
return al.AllowList.Allow(udpAddr)
}
func (al *RemoteAllowList) AllowAll(vpnAddrs []netip.Addr, udpAddr netip.Addr) bool {
if !al.AllowList.Allow(udpAddr) {
return false
}
for _, vpnAddr := range vpnAddrs {
if !al.getInsideAllowList(vpnAddr).Allow(udpAddr) {
return false
}
}
return true
}
func (al *RemoteAllowList) getInsideAllowList(vpnAddr netip.Addr) *AllowList {
if al.insideAllowLists != nil {
inside, ok := al.insideAllowLists.Lookup(vpnAddr)
if ok {
return inside
}
}
return nil
}
================================================
FILE: allow_list_test.go
================================================
package nebula
import (
"net/netip"
"regexp"
"testing"
"github.com/gaissmai/bart"
"github.com/slackhq/nebula/config"
"github.com/slackhq/nebula/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewAllowListFromConfig(t *testing.T) {
l := test.NewLogger()
c := config.NewC(l)
c.Settings["allowlist"] = map[string]any{
"192.168.0.0": true,
}
r, err := newAllowListFromConfig(c, "allowlist", nil)
require.EqualError(t, err, "config `allowlist` has invalid CIDR: 192.168.0.0. netip.ParsePrefix(\"192.168.0.0\"): no '/'")
assert.Nil(t, r)
c.Settings["allowlist"] = map[string]any{
"192.168.0.0/16": "abc",
}
r, err = newAllowListFromConfig(c, "allowlist", nil)
require.EqualError(t, err, "config `allowlist` has invalid value (type string): abc")
c.Settings["allowlist"] = map[string]any{
"192.168.0.0/16": true,
"10.0.0.0/8": false,
}
r, err = newAllowListFromConfig(c, "allowlist", nil)
require.EqualError(t, err, "config `allowlist` contains both true and false rules, but no default set for 0.0.0.0/0")
c.Settings["allowlist"] = map[string]any{
"0.0.0.0/0": true,
"10.0.0.0/8": false,
"10.42.42.0/24": true,
"fd00::/8": true,
"fd00:fd00::/16": false,
}
r, err = newAllowListFromConfig(c, "allowlist", nil)
require.EqualError(t, err, "config `allowlist` contains both true and false rules, but no default set for ::/0")
c.Settings["allowlist"] = map[string]any{
"0.0.0.0/0": true,
"10.0.0.0/8": false,
"10.42.42.0/24": true,
}
r, err = newAllowListFromConfig(c, "allowlist", nil)
if assert.NoError(t, err) {
assert.NotNil(t, r)
}
c.Settings["allowlist"] = map[string]any{
"0.0.0.0/0": true,
"10.0.0.0/8": false,
"10.42.42.0/24": true,
"::/0": false,
"fd00::/8": true,
"fd00:fd00::/16": false,
}
r, err = newAllowListFromConfig(c, "allowlist", nil)
if assert.NoError(t, err) {
assert.NotNil(t, r)
}
// Test interface names
c.Settings["allowlist"] = map[string]any{
"interfaces": map[string]any{
`docker.*`: "foo",
},
}
lr, err := NewLocalAllowListFromConfig(c, "allowlist")
require.EqualError(t, err, "config `allowlist.interfaces` has invalid value (type string): foo")
c.Settings["allowlist"] = map[string]any{
"interfaces": map[string]any{
`docker.*`: false,
`eth.*`: true,
},
}
lr, err = NewLocalAllowListFromConfig(c, "allowlist")
require.EqualError(t, err, "config `allowlist.interfaces` values must all be the same true/false value")
c.Settings["allowlist"] = map[string]any{
"interfaces": map[string]any{
`docker.*`: false,
},
}
lr, err = NewLocalAllowListFromConfig(c, "allowlist")
if assert.NoError(t, err) {
assert.NotNil(t, lr)
}
}
func TestAllowList_Allow(t *testing.T) {
assert.True(t, ((*AllowList)(nil)).Allow(netip.MustParseAddr("1.1.1.1")))
tree := new(bart.Table[bool])
tree.Insert(netip.MustParsePrefix("0.0.0.0/0"), true)
tree.Insert(netip.MustParsePrefix("10.0.0.0/8"), false)
tree.Insert(netip.MustParsePrefix("10.42.42.42/32"), true)
tree.Insert(netip.MustParsePrefix("10.42.0.0/16"), true)
tree.Insert(netip.MustParsePrefix("10.42.42.0/24"), true)
tree.Insert(netip.MustParsePrefix("10.42.42.0/24"), false)
tree.Insert(netip.MustParsePrefix("::1/128"), true)
tree.Insert(netip.MustParsePrefix("::2/128"), false)
al := &AllowList{cidrTree: tree}
assert.True(t, al.Allow(netip.MustParseAddr("1.1.1.1")))
assert.False(t, al.Allow(netip.MustParseAddr("10.0.0.4")))
assert.True(t, al.Allow(netip.MustParseAddr("10.42.42.42")))
assert.False(t, al.Allow(netip.MustParseAddr("10.42.42.41")))
assert.True(t, al.Allow(netip.MustParseAddr("10.42.0.1")))
assert.True(t, al.Allow(netip.MustParseAddr("::1")))
assert.False(t, al.Allow(netip.MustParseAddr("::2")))
}
func TestLocalAllowList_AllowName(t *testing.T) {
assert.True(t, ((*LocalAllowList)(nil)).AllowName("docker0"))
rules := []AllowListNameRule{
{Name: regexp.MustCompile("^docker.*$"), Allow: false},
{Name: regexp.MustCompile("^tun.*$"), Allow: false},
}
al := &LocalAllowList{nameRules: rules}
assert.False(t, al.AllowName("docker0"))
assert.False(t, al.AllowName("tun0"))
assert.True(t, al.AllowName("eth0"))
rules = []AllowListNameRule{
{Name: regexp.MustCompile("^eth.*$"), Allow: true},
{Name: regexp.MustCompile("^ens.*$"), Allow: true},
}
al = &LocalAllowList{nameRules: rules}
assert.False(t, al.AllowName("docker0"))
assert.True(t, al.AllowName("eth0"))
assert.True(t, al.AllowName("ens5"))
}
================================================
FILE: bits.go
================================================
package nebula
import (
"github.com/rcrowley/go-metrics"
"github.com/sirupsen/logrus"
)
type Bits struct {
length uint64
current uint64
bits []bool
lostCounter metrics.Counter
dupeCounter metrics.Counter
outOfWindowCounter metrics.Counter
}
func NewBits(bits uint64) *Bits {
b := &Bits{
length: bits,
bits: make([]bool, bits, bits),
current: 0,
lostCounter: metrics.GetOrRegisterCounter("network.packets.lost", nil),
dupeCounter: metrics.GetOrRegisterCounter("network.packets.duplicate", nil),
outOfWindowCounter: metrics.GetOrRegisterCounter("network.packets.out_of_window", nil),
}
// There is no counter value 0, mark it to avoid counting a lost packet later.
b.bits[0] = true
b.current = 0
return b
}
func (b *Bits) Check(l *logrus.Logger, i uint64) bool {
// If i is the next number, return true.
if i > b.current {
return true
}
// If i is within the window, check if it's been set already.
if i > b.current-b.length || i < b.length && b.current < b.length {
return !b.bits[i%b.length]
}
// Not within the window
if l.Level >= logrus.DebugLevel {
l.Debugf("rejected a packet (top) %d %d\n", b.current, i)
}
return false
}
func (b *Bits) Update(l *logrus.Logger, i uint64) bool {
// If i is the next number, return true and update current.
if i == b.current+1 {
// Check if the oldest bit was lost since we are shifting the window by 1 and occupying it with this counter
// The very first window can only be tracked as lost once we are on the 2nd window or greater
if b.bits[i%b.length] == false && i > b.length {
b.lostCounter.Inc(1)
}
b.bits[i%b.length] = true
b.current = i
return true
}
// If i is a jump, adjust the window, record lost, update current, and return true
if i > b.current {
lost := int64(0)
// Zero out the bits between the current and the new counter value, limited by the window size,
// since the window is shifting
for n := b.current + 1; n <= min(i, b.current+b.length); n++ {
if b.bits[n%b.length] == false && n > b.length {
lost++
}
b.bits[n%b.length] = false
}
// Only record any skipped packets as a result of the window moving further than the window length
// Any loss within the new window will be accounted for in future calls
lost += max(0, int64(i-b.current-b.length))
b.lostCounter.Inc(lost)
b.bits[i%b.length] = true
b.current = i
return true
}
// If i is within the current window but below the current counter,
// Check to see if it's a duplicate
if i > b.current-b.length || i < b.length && b.current < b.length {
if b.current == i || b.bits[i%b.length] == true {
if l.Level >= logrus.DebugLevel {
l.WithField("receiveWindow", m{"accepted": false, "currentCounter": b.current, "incomingCounter": i, "reason": "duplicate"}).
Debug("Receive window")
}
b.dupeCounter.Inc(1)
return false
}
b.bits[i%b.length] = true
return true
}
// In all other cases, fail and don't change current.
b.outOfWindowCounter.Inc(1)
if l.Level >= logrus.DebugLevel {
l.WithField("accepted", false).
WithField("currentCounter", b.current).
WithField("incomingCounter", i).
WithField("reason", "nonsense").
Debug("Receive window")
}
return false
}
================================================
FILE: bits_test.go
================================================
package nebula
import (
"testing"
"github.com/slackhq/nebula/test"
"github.com/stretchr/testify/assert"
)
func TestBits(t *testing.T) {
l := test.NewLogger()
b := NewBits(10)
// make sure it is the right size
assert.Len(t, b.bits, 10)
// This is initialized to zero - receive one. This should work.
assert.True(t, b.Check(l, 1))
assert.True(t, b.Update(l, 1))
assert.EqualValues(t, 1, b.current)
g := []bool{true, true, false, false, false, false, false, false, false, false}
assert.Equal(t, g, b.bits)
// Receive two
assert.True(t, b.Check(l, 2))
assert.True(t, b.Update(l, 2))
assert.EqualValues(t, 2, b.current)
g = []bool{true, true, true, false, false, false, false, false, false, false}
assert.Equal(t, g, b.bits)
// Receive two again - it will fail
assert.False(t, b.Check(l, 2))
assert.False(t, b.Update(l, 2))
assert.EqualValues(t, 2, b.current)
// Jump ahead to 15, which should clear everything and set the 6th element
assert.True(t, b.Check(l, 15))
assert.True(t, b.Update(l, 15))
assert.EqualValues(t, 15, b.current)
g = []bool{false, false, false, false, false, true, false, false, false, false}
assert.Equal(t, g, b.bits)
// Mark 14, which is allowed because it is in the window
assert.True(t, b.Check(l, 14))
assert.True(t, b.Update(l, 14))
assert.EqualValues(t, 15, b.current)
g = []bool{false, false, false, false, true, true, false, false, false, false}
assert.Equal(t, g, b.bits)
// Mark 5, which is not allowed because it is not in the window
assert.False(t, b.Check(l, 5))
assert.False(t, b.Update(l, 5))
assert.EqualValues(t, 15, b.current)
g = []bool{false, false, false, false, true, true, false, false, false, false}
assert.Equal(t, g, b.bits)
// make sure we handle wrapping around once to the current position
b = NewBits(10)
assert.True(t, b.Update(l, 1))
assert.True(t, b.Update(l, 11))
assert.Equal(t, []bool{false, true, false, false, false, false, false, false, false, false}, b.bits)
// Walk through a few windows in order
b = NewBits(10)
for i := uint64(1); i <= 100; i++ {
assert.True(t, b.Check(l, i), "Error while checking %v", i)
assert.True(t, b.Update(l, i), "Error while updating %v", i)
}
assert.False(t, b.Check(l, 1), "Out of window check")
}
func TestBitsLargeJumps(t *testing.T) {
l := test.NewLogger()
b := NewBits(10)
b.lostCounter.Clear()
b = NewBits(10)
b.lostCounter.Clear()
assert.True(t, b.Update(l, 55)) // We saw packet 55 and can still track 45,46,47,48,49,50,51,52,53,54
assert.Equal(t, int64(45), b.lostCounter.Count())
assert.True(t, b.Update(l, 100)) // We saw packet 55 and 100 and can still track 90,91,92,93,94,95,96,97,98,99
assert.Equal(t, int64(89), b.lostCounter.Count())
assert.True(t, b.Update(l, 200)) // We saw packet 55, 100, and 200 and can still track 190,191,192,193,194,195,196,197,198,199
assert.Equal(t, int64(188), b.lostCounter.Count())
}
func TestBitsDupeCounter(t *testing.T) {
l := test.NewLogger()
b := NewBits(10)
b.lostCounter.Clear()
b.dupeCounter.Clear()
b.outOfWindowCounter.Clear()
assert.True(t, b.Update(l, 1))
assert.Equal(t, int64(0), b.dupeCounter.Count())
assert.False(t, b.Update(l, 1))
assert.Equal(t, int64(1), b.dupeCounter.Count())
assert.True(t, b.Update(l, 2))
assert.Equal(t, int64(1), b.dupeCounter.Count())
assert.True(t, b.Update(l, 3))
assert.Equal(t, int64(1), b.dupeCounter.Count())
assert.False(t, b.Update(l, 1))
assert.Equal(t, int64(0), b.lostCounter.Count())
assert.Equal(t, int64(2), b.dupeCounter.Count())
assert.Equal(t, int64(0), b.outOfWindowCounter.Count())
}
func TestBitsOutOfWindowCounter(t *testing.T) {
l := test.NewLogger()
b := NewBits(10)
b.lostCounter.Clear()
b.dupeCounter.Clear()
b.outOfWindowCounter.Clear()
assert.True(t, b.Update(l, 20))
assert.Equal(t, int64(0), b.outOfWindowCounter.Count())
assert.True(t, b.Update(l, 21))
assert.True(t, b.Update(l, 22))
assert.True(t, b.Update(l, 23))
assert.True(t, b.Update(l, 24))
assert.True(t, b.Update(l, 25))
assert.True(t, b.Update(l, 26))
assert.True(t, b.Update(l, 27))
assert.True(t, b.Update(l, 28))
assert.True(t, b.Update(l, 29))
assert.Equal(t, int64(0), b.outOfWindowCounter.Count())
assert.False(t, b.Update(l, 0))
assert.Equal(t, int64(1), b.outOfWindowCounter.Count())
assert.Equal(t, int64(19), b.lostCounter.Count()) // packet 0 wasn't lost
assert.Equal(t, int64(0), b.dupeCounter.Count())
assert.Equal(t, int64(1), b.outOfWindowCounter.Count())
}
func TestBitsLostCounter(t *testing.T) {
l := test.NewLogger()
b := NewBits(10)
b.lostCounter.Clear()
b.dupeCounter.Clear()
b.outOfWindowCounter.Clear()
assert.True(t, b.Update(l, 20))
assert.True(t, b.Update(l, 21))
assert.True(t, b.Update(l, 22))
assert.True(t, b.Update(l, 23))
assert.True(t, b.Update(l, 24))
assert.True(t, b.Update(l, 25))
assert.True(t, b.Update(l, 26))
assert.True(t, b.Update(l, 27))
assert.True(t, b.Update(l, 28))
assert.True(t, b.Update(l, 29))
assert.Equal(t, int64(19), b.lostCounter.Count()) // packet 0 wasn't lost
assert.Equal(t, int64(0), b.dupeCounter.Count())
assert.Equal(t, int64(0), b.outOfWindowCounter.Count())
b = NewBits(10)
b.lostCounter.Clear()
b.dupeCounter.Clear()
b.outOfWindowCounter.Clear()
assert.True(t, b.Update(l, 9))
assert.Equal(t, int64(0), b.lostCounter.Count())
// 10 will set 0 index, 0 was already set, no lost packets
assert.True(t, b.Update(l, 10))
assert.Equal(t, int64(0), b.lostCounter.Count())
// 11 will set 1 index, 1 was missed, we should see 1 packet lost
assert.True(t, b.Update(l, 11))
assert.Equal(t, int64(1), b.lostCounter.Count())
// Now let's fill in the window, should end up with 8 lost packets
assert.True(t, b.Update(l, 12))
assert.True(t, b.Update(l, 13))
assert.True(t, b.Update(l, 14))
assert.True(t, b.Update(l, 15))
assert.True(t, b.Update(l, 16))
assert.True(t, b.Update(l, 17))
assert.True(t, b.Update(l, 18))
assert.True(t, b.Update(l, 19))
assert.Equal(t, int64(8), b.lostCounter.Count())
// Jump ahead by a window size
assert.True(t, b.Update(l, 29))
assert.Equal(t, int64(8), b.lostCounter.Count())
// Now lets walk ahead normally through the window, the missed packets should fill in
assert.True(t, b.Update(l, 30))
assert.True(t, b.Update(l, 31))
assert.True(t, b.Update(l, 32))
assert.True(t, b.Update(l, 33))
assert.True(t, b.Update(l, 34))
assert.True(t, b.Update(l, 35))
assert.True(t, b.Update(l, 36))
assert.True(t, b.Update(l, 37))
assert.True(t, b.Update(l, 38))
// 39 packets tracked, 22 seen, 17 lost
assert.Equal(t, int64(17), b.lostCounter.Count())
// Jump ahead by 2 windows, should have recording 1 full window missing
assert.True(t, b.Update(l, 58))
assert.Equal(t, int64(27), b.lostCounter.Count())
// Now lets walk ahead normally through the window, the missed packets should fill in from this window
assert.True(t, b.Update(l, 59))
assert.True(t, b.Update(l, 60))
assert.True(t, b.Update(l, 61))
assert.True(t, b.Update(l, 62))
assert.True(t, b.Update(l, 63))
assert.True(t, b.Update(l, 64))
assert.True(t, b.Update(l, 65))
assert.True(t, b.Update(l, 66))
assert.True(t, b.Update(l, 67))
// 68 packets tracked, 32 seen, 36 missed
assert.Equal(t, int64(36), b.lostCounter.Count())
assert.Equal(t, int64(0), b.dupeCounter.Count())
assert.Equal(t, int64(0), b.outOfWindowCounter.Count())
}
func TestBitsLostCounterIssue1(t *testing.T) {
l := test.NewLogger()
b := NewBits(10)
b.lostCounter.Clear()
b.dupeCounter.Clear()
b.outOfWindowCounter.Clear()
assert.True(t, b.Update(l, 4))
assert.Equal(t, int64(0), b.lostCounter.Count())
assert.True(t, b.Update(l, 1))
assert.Equal(t, int64(0), b.lostCounter.Count())
assert.True(t, b.Update(l, 9))
assert.Equal(t, int64(0), b.lostCounter.Count())
assert.True(t, b.Update(l, 2))
assert.Equal(t, int64(0), b.lostCounter.Count())
assert.True(t, b.Update(l, 3))
assert.Equal(t, int64(0), b.lostCounter.Count())
assert.True(t, b.Update(l, 5))
assert.Equal(t, int64(0), b.lostCounter.Count())
assert.True(t, b.Update(l, 6))
assert.Equal(t, int64(0), b.lostCounter.Count())
assert.True(t, b.Update(l, 7))
assert.Equal(t, int64(0), b.lostCounter.Count())
// assert.True(t, b.Update(l, 8))
assert.True(t, b.Update(l, 10))
assert.Equal(t, int64(0), b.lostCounter.Count())
assert.True(t, b.Update(l, 11))
assert.Equal(t, int64(0), b.lostCounter.Count())
assert.True(t, b.Update(l, 14))
assert.Equal(t, int64(0), b.lostCounter.Count())
// Issue seems to be here, we reset missing packet 8 to false here and don't increment the lost counter
assert.True(t, b.Update(l, 19))
assert.Equal(t, int64(1), b.lostCounter.Count())
assert.True(t, b.Update(l, 12))
assert.Equal(t, int64(1), b.lostCounter.Count())
assert.True(t, b.Update(l, 13))
assert.Equal(t, int64(1), b.lostCounter.Count())
assert.True(t, b.Update(l, 15))
assert.Equal(t, int64(1), b.lostCounter.Count())
assert.True(t, b.Update(l, 16))
assert.Equal(t, int64(1), b.lostCounter.Count())
assert.True(t, b.Update(l, 17))
assert.Equal(t, int64(1), b.lostCounter.Count())
assert.True(t, b.Update(l, 18))
assert.Equal(t, int64(1), b.lostCounter.Count())
assert.True(t, b.Update(l, 20))
assert.Equal(t, int64(1), b.lostCounter.Count())
assert.True(t, b.Update(l, 21))
// We missed packet 8 above
assert.Equal(t, int64(1), b.lostCounter.Count())
assert.Equal(t, int64(0), b.dupeCounter.Count())
assert.Equal(t, int64(0), b.outOfWindowCounter.Count())
}
func BenchmarkBits(b *testing.B) {
z := NewBits(10)
for n := 0; n < b.N; n++ {
for i := range z.bits {
z.bits[i] = true
}
for i := range z.bits {
z.bits[i] = false
}
}
}
================================================
FILE: boring.go
================================================
//go:build boringcrypto
package nebula
import "crypto/boring"
var boringEnabled = boring.Enabled
================================================
FILE: calculated_remote.go
================================================
package nebula
import (
"encoding/binary"
"fmt"
"math"
"net"
"net/netip"
"strconv"
"github.com/gaissmai/bart"
"github.com/slackhq/nebula/config"
)
// This allows us to "guess" what the remote might be for a host while we wait
// for the lighthouse response. See "lighthouse.calculated_remotes" in the
// example config file.
type calculatedRemote struct {
ipNet netip.Prefix
mask netip.Prefix
port uint32
}
func newCalculatedRemote(cidr, maskCidr netip.Prefix, port int) (*calculatedRemote, error) {
if maskCidr.Addr().BitLen() != cidr.Addr().BitLen() {
return nil, fmt.Errorf("invalid mask: %s for cidr: %s", maskCidr, cidr)
}
masked := maskCidr.Masked()
if port < 0 || port > math.MaxUint16 {
return nil, fmt.Errorf("invalid port: %d", port)
}
return &calculatedRemote{
ipNet: maskCidr,
mask: masked,
port: uint32(port),
}, nil
}
func (c *calculatedRemote) String() string {
return fmt.Sprintf("CalculatedRemote(mask=%v port=%d)", c.ipNet, c.port)
}
func (c *calculatedRemote) ApplyV4(addr netip.Addr) *V4AddrPort {
// Combine the masked bytes of the "mask" IP with the unmasked bytes of the overlay IP
maskb := net.CIDRMask(c.mask.Bits(), c.mask.Addr().BitLen())
mask := binary.BigEndian.Uint32(maskb[:])
b := c.mask.Addr().As4()
maskAddr := binary.BigEndian.Uint32(b[:])
b = addr.As4()
intAddr := binary.BigEndian.Uint32(b[:])
return &V4AddrPort{(maskAddr & mask) | (intAddr & ^mask), c.port}
}
func (c *calculatedRemote) ApplyV6(addr netip.Addr) *V6AddrPort {
mask := net.CIDRMask(c.mask.Bits(), c.mask.Addr().BitLen())
maskAddr := c.mask.Addr().As16()
calcAddr := addr.As16()
ap := V6AddrPort{Port: c.port}
maskb := binary.BigEndian.Uint64(mask[:8])
maskAddrb := binary.BigEndian.Uint64(maskAddr[:8])
calcAddrb := binary.BigEndian.Uint64(calcAddr[:8])
ap.Hi = (maskAddrb & maskb) | (calcAddrb & ^maskb)
maskb = binary.BigEndian.Uint64(mask[8:])
maskAddrb = binary.BigEndian.Uint64(maskAddr[8:])
calcAddrb = binary.BigEndian.Uint64(calcAddr[8:])
ap.Lo = (maskAddrb & maskb) | (calcAddrb & ^maskb)
return &ap
}
func NewCalculatedRemotesFromConfig(c *config.C, k string) (*bart.Table[[]*calculatedRemote], error) {
value := c.Get(k)
if value == nil {
return nil, nil
}
calculatedRemotes := new(bart.Table[[]*calculatedRemote])
rawMap, ok := value.(map[string]any)
if !ok {
return nil, fmt.Errorf("config `%s` has invalid type: %T", k, value)
}
for rawCIDR, rawValue := range rawMap {
cidr, err := netip.ParsePrefix(rawCIDR)
if err != nil {
return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)
}
entry, err := newCalculatedRemotesListFromConfig(cidr, rawValue)
if err != nil {
return nil, fmt.Errorf("config '%s.%s': %w", k, rawCIDR, err)
}
calculatedRemotes.Insert(cidr, entry)
}
return calculatedRemotes, nil
}
func newCalculatedRemotesListFromConfig(cidr netip.Prefix, raw any) ([]*calculatedRemote, error) {
rawList, ok := raw.([]any)
if !ok {
return nil, fmt.Errorf("calculated_remotes entry has invalid type: %T", raw)
}
var l []*calculatedRemote
for _, e := range rawList {
c, err := newCalculatedRemotesEntryFromConfig(cidr, e)
if err != nil {
return nil, fmt.Errorf("calculated_remotes entry: %w", err)
}
l = append(l, c)
}
return l, nil
}
func newCalculatedRemotesEntryFromConfig(cidr netip.Prefix, raw any) (*calculatedRemote, error) {
rawMap, ok := raw.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid type: %T", raw)
}
rawValue := rawMap["mask"]
if rawValue == nil {
return nil, fmt.Errorf("missing mask: %v", rawMap)
}
rawMask, ok := rawValue.(string)
if !ok {
return nil, fmt.Errorf("invalid mask (type %T): %v", rawValue, rawValue)
}
maskCidr, err := netip.ParsePrefix(rawMask)
if err != nil {
return nil, fmt.Errorf("invalid mask: %s", rawMask)
}
var port int
rawValue = rawMap["port"]
if rawValue == nil {
return nil, fmt.Errorf("missing port: %v", rawMap)
}
switch v := rawValue.(type) {
case int:
port = v
case string:
port, err = strconv.Atoi(v)
if err != nil {
return nil, fmt.Errorf("invalid port: %s: %w", v, err)
}
default:
return nil, fmt.Errorf("invalid port (type %T): %v", rawValue, rawValue)
}
return newCalculatedRemote(cidr, maskCidr, port)
}
================================================
FILE: calculated_remote_test.go
================================================
package nebula
import (
"net/netip"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCalculatedRemoteApply(t *testing.T) {
// Test v4 addresses
ipNet := netip.MustParsePrefix("192.168.1.0/24")
c, err := newCalculatedRemote(ipNet, ipNet, 4242)
require.NoError(t, err)
input, err := netip.ParseAddr("10.0.10.182")
require.NoError(t, err)
expected, err := netip.ParseAddr("192.168.1.182")
require.NoError(t, err)
assert.Equal(t, netAddrToProtoV4AddrPort(expected, 4242), c.ApplyV4(input))
// Test v6 addresses
ipNet = netip.MustParsePrefix("ffff:ffff:ffff:ffff::0/64")
c, err = newCalculatedRemote(ipNet, ipNet, 4242)
require.NoError(t, err)
input, err = netip.ParseAddr("beef:beef:beef:beef:beef:beef:beef:beef")
require.NoError(t, err)
expected, err = netip.ParseAddr("ffff:ffff:ffff:ffff:beef:beef:beef:beef")
require.NoError(t, err)
assert.Equal(t, netAddrToProtoV6AddrPort(expected, 4242), c.ApplyV6(input))
// Test v6 addresses part 2
ipNet = netip.MustParsePrefix("ffff:ffff:ffff:ffff:ffff::0/80")
c, err = newCalculatedRemote(ipNet, ipNet, 4242)
require.NoError(t, err)
input, err = netip.ParseAddr("beef:beef:beef:beef:beef:beef:beef:beef")
require.NoError(t, err)
expected, err = netip.ParseAddr("ffff:ffff:ffff:ffff:ffff:beef:beef:beef")
require.NoError(t, err)
assert.Equal(t, netAddrToProtoV6AddrPort(expected, 4242), c.ApplyV6(input))
// Test v6 addresses part 2
ipNet = netip.MustParsePrefix("ffff:ffff:ffff::0/48")
c, err = newCalculatedRemote(ipNet, ipNet, 4242)
require.NoError(t, err)
input, err = netip.ParseAddr("beef:beef:beef:beef:beef:beef:beef:beef")
require.NoError(t, err)
expected, err = netip.ParseAddr("ffff:ffff:ffff:beef:beef:beef:beef:beef")
require.NoError(t, err)
assert.Equal(t, netAddrToProtoV6AddrPort(expected, 4242), c.ApplyV6(input))
}
func Test_newCalculatedRemote(t *testing.T) {
c, err := newCalculatedRemote(netip.MustParsePrefix("1::1/128"), netip.MustParsePrefix("1.0.0.0/32"), 4242)
require.EqualError(t, err, "invalid mask: 1.0.0.0/32 for cidr: 1::1/128")
require.Nil(t, c)
c, err = newCalculatedRemote(netip.MustParsePrefix("1.0.0.0/32"), netip.MustParsePrefix("1::1/128"), 4242)
require.EqualError(t, err, "invalid mask: 1::1/128 for cidr: 1.0.0.0/32")
require.Nil(t, c)
c, err = newCalculatedRemote(netip.MustParsePrefix("1.0.0.0/32"), netip.MustParsePrefix("1.0.0.0/32"), 4242)
require.NoError(t, err)
require.NotNil(t, c)
c, err = newCalculatedRemote(netip.MustParsePrefix("1::1/128"), netip.MustParsePrefix("1::1/128"), 4242)
require.NoError(t, err)
require.NotNil(t, c)
}
================================================
FILE: cert/Makefile
================================================
GO111MODULE = on
export GO111MODULE
cert_v1.pb.go: cert_v1.proto .FORCE
go build google.golang.org/protobuf/cmd/protoc-gen-go
PATH="$(CURDIR):$(PATH)" protoc --go_out=. --go_opt=paths=source_relative $<
rm protoc-gen-go
.FORCE:
================================================
FILE: cert/README.md
================================================
## `cert`
This is a library for interacting with `nebula` style certificates and authorities.
There are now 2 versions of `nebula` certificates:
## v1
This version is deprecated.
A `protobuf` definition of the certificate format is included at `cert_v1.proto`
To compile the definition you will need `protoc` installed.
To compile for `go` with the same version of protobuf specified in go.mod:
```bash
make proto
```
## v2
This is the latest version which uses asn.1 DER encoding. It can support ipv4 and ipv6 and tolerate
future certificate changes better than v1.
`cert_v2.asn1` defines the wire format and can be used to compile marshalers.
================================================
FILE: cert/asn1.go
================================================
package cert
import (
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
)
// readOptionalASN1Boolean reads an asn.1 boolean with a specific tag instead of a asn.1 tag wrapping a boolean with a value
// https://github.com/golang/go/issues/64811#issuecomment-1944446920
func readOptionalASN1Boolean(b *cryptobyte.String, out *bool, tag asn1.Tag, defaultValue bool) bool {
var present bool
var child cryptobyte.String
if !b.ReadOptionalASN1(&child, &present, tag) {
return false
}
if !present {
*out = defaultValue
return true
}
// Ensure we have 1 byte
if len(child) == 1 {
*out = child[0] > 0
return true
}
return false
}
// readOptionalASN1Byte reads an asn.1 uint8 with a specific tag instead of a asn.1 tag wrapping a uint8 with a value
// Similar issue as with readOptionalASN1Boolean
func readOptionalASN1Byte(b *cryptobyte.String, out *byte, tag asn1.Tag, defaultValue byte) bool {
var present bool
var child cryptobyte.String
if !b.ReadOptionalASN1(&child, &present, tag) {
return false
}
if !present {
*out = defaultValue
return true
}
// Ensure we have 1 byte
if len(child) == 1 {
*out = child[0]
return true
}
return false
}
================================================
FILE: cert/ca_pool.go
================================================
package cert
import (
"errors"
"fmt"
"net/netip"
"slices"
"strings"
"time"
)
type CAPool struct {
CAs map[string]*CachedCertificate
certBlocklist map[string]struct{}
}
// NewCAPool creates an empty CAPool
func NewCAPool() *CAPool {
ca := CAPool{
CAs: make(map[string]*CachedCertificate),
certBlocklist: make(map[string]struct{}),
}
return &ca
}
// NewCAPoolFromPEM will create a new CA pool from the provided
// input bytes, which must be a PEM-encoded set of nebula certificates.
// If the pool contains any expired certificates, an ErrExpired will be
// returned along with the pool. The caller must handle any such errors.
func NewCAPoolFromPEM(caPEMs []byte) (*CAPool, error) {
pool := NewCAPool()
var err error
var expired bool
for {
caPEMs, err = pool.AddCAFromPEM(caPEMs)
if errors.Is(err, ErrExpired) {
expired = true
err = nil
}
if err != nil {
return nil, err
}
if len(caPEMs) == 0 || strings.TrimSpace(string(caPEMs)) == "" {
break
}
}
if expired {
return pool, ErrExpired
}
return pool, nil
}
// AddCAFromPEM verifies a Nebula CA certificate and adds it to the pool.
// Only the first pem encoded object will be consumed, any remaining bytes are returned.
// Parsed certificates will be verified and must be a CA
func (ncp *CAPool) AddCAFromPEM(pemBytes []byte) ([]byte, error) {
c, pemBytes, err := UnmarshalCertificateFromPEM(pemBytes)
if err != nil {
return pemBytes, err
}
err = ncp.AddCA(c)
if err != nil {
return pemBytes, err
}
return pemBytes, nil
}
// AddCA verifies a Nebula CA certificate and adds it to the pool.
func (ncp *CAPool) AddCA(c Certificate) error {
if !c.IsCA() {
return fmt.Errorf("%s: %w", c.Name(), ErrNotCA)
}
if !c.CheckSignature(c.PublicKey()) {
return fmt.Errorf("%s: %w", c.Name(), ErrNotSelfSigned)
}
sum, err := c.Fingerprint()
if err != nil {
return fmt.Errorf("could not calculate fingerprint for provided CA; error: %w; %s", err, c.Name())
}
cc := &CachedCertificate{
Certificate: c,
Fingerprint: sum,
InvertedGroups: make(map[string]struct{}),
}
for _, g := range c.Groups() {
cc.InvertedGroups[g] = struct{}{}
}
ncp.CAs[sum] = cc
if c.Expired(time.Now()) {
return fmt.Errorf("%s: %w", c.Name(), ErrExpired)
}
return nil
}
// BlocklistFingerprint adds a cert fingerprint to the blocklist
func (ncp *CAPool) BlocklistFingerprint(f string) {
ncp.certBlocklist[f] = struct{}{}
}
// ResetCertBlocklist removes all previously blocklisted cert fingerprints
func (ncp *CAPool) ResetCertBlocklist() {
ncp.certBlocklist = make(map[string]struct{})
}
// IsBlocklisted tests the provided fingerprint against the pools blocklist.
// Returns true if the fingerprint is blocked.
func (ncp *CAPool) IsBlocklisted(fingerprint string) bool {
if _, ok := ncp.certBlocklist[fingerprint]; ok {
return true
}
return false
}
// VerifyCertificate verifies the certificate is valid and is signed by a trusted CA in the pool.
// If the certificate is valid then the returned CachedCertificate can be used in subsequent verification attempts
// to increase performance.
func (ncp *CAPool) VerifyCertificate(now time.Time, c Certificate) (*CachedCertificate, error) {
if c == nil {
return nil, fmt.Errorf("no certificate")
}
fp, err := c.Fingerprint()
if err != nil {
return nil, fmt.Errorf("could not calculate fingerprint to verify: %w", err)
}
signer, err := ncp.verify(c, now, fp, "")
if err != nil {
return nil, err
}
// Pre nebula v1.10.3 could generate signatures in either high or low s form and validation
// of signatures allowed for either. Nebula v1.10.3 and beyond clamps signature generation to low-s form
// but validation still allows for either. Since a change in the signature bytes affects the fingerprint, we
// need to test both forms until such a time comes that we enforce low-s form on signature validation.
fp2, err := CalculateAlternateFingerprint(c)
if err != nil {
return nil, fmt.Errorf("could not calculate alternate fingerprint to verify: %w", err)
}
if fp2 != "" && ncp.IsBlocklisted(fp2) {
return nil, ErrBlockListed
}
cc := CachedCertificate{
Certificate: c,
InvertedGroups: make(map[string]struct{}),
Fingerprint: fp,
fingerprint2: fp2,
signerFingerprint: signer.Fingerprint,
}
for _, g := range c.Groups() {
cc.InvertedGroups[g] = struct{}{}
}
return &cc, nil
}
// VerifyCachedCertificate is the same as VerifyCertificate other than it operates on a pre-verified structure and
// is a cheaper operation to perform as a result.
func (ncp *CAPool) VerifyCachedCertificate(now time.Time, c *CachedCertificate) error {
// Check any available alternate fingerprint forms for this certificate, re P256 high-s/low-s
if c.fingerprint2 != "" && ncp.IsBlocklisted(c.fingerprint2) {
return ErrBlockListed
}
_, err := ncp.verify(c.Certificate, now, c.Fingerprint, c.signerFingerprint)
return err
}
func (ncp *CAPool) verify(c Certificate, now time.Time, certFp string, signerFp string) (*CachedCertificate, error) {
if ncp.IsBlocklisted(certFp) {
return nil, ErrBlockListed
}
signer, err := ncp.GetCAForCert(c)
if err != nil {
return nil, err
}
if signer.Certificate.Expired(now) {
return nil, ErrRootExpired
}
if c.Expired(now) {
return nil, ErrExpired
}
// If we are checking a cached certificate then we can bail early here
// Either the root is no longer trusted or everything is fine
if len(signerFp) > 0 {
if signerFp != signer.Fingerprint {
return nil, ErrFingerprintMismatch
}
return signer, nil
}
if !c.CheckSignature(signer.Certificate.PublicKey()) {
return nil, ErrSignatureMismatch
}
err = CheckCAConstraints(signer.Certificate, c)
if err != nil {
return nil, err
}
return signer, nil
}
// GetCAForCert attempts to return the signing certificate for the provided certificate.
// No signature validation is performed
func (ncp *CAPool) GetCAForCert(c Certificate) (*CachedCertificate, error) {
issuer := c.Issuer()
if issuer == "" {
return nil, fmt.Errorf("no issuer in certificate")
}
signer, ok := ncp.CAs[issuer]
if ok {
return signer, nil
}
return nil, ErrCaNotFound
}
// GetFingerprints returns an array of trusted CA fingerprints
func (ncp *CAPool) GetFingerprints() []string {
fp := make([]string, len(ncp.CAs))
i := 0
for k := range ncp.CAs {
fp[i] = k
i++
}
return fp
}
// CheckCAConstraints returns an error if the sub certificate violates constraints present in the signer certificate.
func CheckCAConstraints(signer Certificate, sub Certificate) error {
return checkCAConstraints(signer, sub.NotBefore(), sub.NotAfter(), sub.Groups(), sub.Networks(), sub.UnsafeNetworks())
}
// checkCAConstraints is a very generic function allowing both Certificates and TBSCertificates to be tested.
func checkCAConstraints(signer Certificate, notBefore, notAfter time.Time, groups []string, networks, unsafeNetworks []netip.Prefix) error {
// Make sure this cert isn't valid after the root
if notAfter.After(signer.NotAfter()) {
return fmt.Errorf("certificate expires after signing certificate")
}
// Make sure this cert wasn't valid before the root
if notBefore.Before(signer.NotBefore()) {
return fmt.Errorf("certificate is valid before the signing certificate")
}
// If the signer has a limited set of groups make sure the cert only contains a subset
signerGroups := signer.Groups()
if len(signerGroups) > 0 {
for _, g := range groups {
if !slices.Contains(signerGroups, g) {
return fmt.Errorf("certificate contained a group not present on the signing ca: %s", g)
}
}
}
// If the signer has a limited set of ip ranges to issue from make sure the cert only contains a subset
signingNetworks := signer.Networks()
if len(signingNetworks) > 0 {
for _, certNetwork := range networks {
found := false
for _, signingNetwork := range signingNetworks {
if signingNetwork.Contains(certNetwork.Addr()) && signingNetwork.Bits() <= certNetwork.Bits() {
found = true
break
}
}
if !found {
return fmt.Errorf("certificate contained a network assignment outside the limitations of the signing ca: %s", certNetwork.String())
}
}
}
// If the signer has a limited set of subnet ranges to issue from make sure the cert only contains a subset
signingUnsafeNetworks := signer.UnsafeNetworks()
if len(signingUnsafeNetworks) > 0 {
for _, certUnsafeNetwork := range unsafeNetworks {
found := false
for _, caNetwork := range signingUnsafeNetworks {
if caNetwork.Contains(certUnsafeNetwork.Addr()) && caNetwork.Bits() <= certUnsafeNetwork.Bits() {
found = true
break
}
}
if !found {
return fmt.Errorf("certificate contained an unsafe network assignment outside the limitations of the signing ca: %s", certUnsafeNetwork.String())
}
}
}
return nil
}
================================================
FILE: cert/ca_pool_test.go
================================================
package cert
import (
"net/netip"
"testing"
"time"
"github.com/slackhq/nebula/cert/p256"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewCAPoolFromBytes(t *testing.T) {
noNewLines := `
# Current provisional, Remove once everything moves over to the real root.
-----BEGIN NEBULA CERTIFICATE-----
Cj4KDm5lYnVsYSByb290IGNhKM0cMM24zPCvBzogV24YEw5YiqeI/oYo8XXFsoo+
PBmiOafNJhLacf9rsspAARJAz9OAnh8TKAUKix1kKVMyQU4iM3LsFfZRf6ODWXIf
2qWMpB6fpd3PSoVYziPoOt2bIHIFLlgRLPJz3I3xBEdBCQ==
-----END NEBULA CERTIFICATE-----
# root-ca01
-----BEGIN NEBULA CERTIFICATE-----
CkEKEW5lYnVsYSByb290IGNhIDAxKM0cMM24zPCvBzogPzbWTxt8ZgXPQEwup7Br
BrtIt1O0q5AuTRT3+t2x1VJAARJAZ+2ib23qBXjdy49oU1YysrwuKkWWKrtJ7Jye
rFBQpDXikOukhQD/mfkloFwJ+Yjsfru7IpTN4ZfjXL+kN/2sCA==
-----END NEBULA CERTIFICATE-----
`
withNewLines := `
# Current provisional, Remove once everything moves over to the real root.
-----BEGIN NEBULA CERTIFICATE-----
Cj4KDm5lYnVsYSByb290IGNhKM0cMM24zPCvBzogV24YEw5YiqeI/oYo8XXFsoo+
PBmiOafNJhLacf9rsspAARJAz9OAnh8TKAUKix1kKVMyQU4iM3LsFfZRf6ODWXIf
2qWMpB6fpd3PSoVYziPoOt2bIHIFLlgRLPJz3I3xBEdBCQ==
-----END NEBULA CERTIFICATE-----
# root-ca01
-----BEGIN NEBULA CERTIFICATE-----
CkEKEW5lYnVsYSByb290IGNhIDAxKM0cMM24zPCvBzogPzbWTxt8ZgXPQEwup7Br
BrtIt1O0q5AuTRT3+t2x1VJAARJAZ+2ib23qBXjdy49oU1YysrwuKkWWKrtJ7Jye
rFBQpDXikOukhQD/mfkloFwJ+Yjsfru7IpTN4ZfjXL+kN/2sCA==
-----END NEBULA CERTIFICATE-----
`
expired := `
# expired certificate
-----BEGIN NEBULA CERTIFICATE-----
CjMKB2V4cGlyZWQozRwwzRw6ICJSG94CqX8wn5I65Pwn25V6HftVfWeIySVtp2DA
7TY/QAESQMaAk5iJT5EnQwK524ZaaHGEJLUqqbh5yyOHhboIGiVTWkFeH3HccTW8
Tq5a8AyWDQdfXbtEZ1FwabeHfH5Asw0=
-----END NEBULA CERTIFICATE-----
`
p256 := `
# p256 certificate
-----BEGIN NEBULA CERTIFICATE-----
CmQKEG5lYnVsYSBQMjU2IHRlc3QozRwwzbjM8K8HOkEEdrmmg40zQp44AkMq6DZp
k+coOv04r+zh33ISyhbsafnYduN17p2eD7CmHvHuerguXD9f32gcxo/KsFCKEjMe
+0ABoAYBEkcwRQIgVoTg38L7uWku9xQgsr06kxZ/viQLOO/w1Qj1vFUEnhcCIQCq
75SjTiV92kv/1GcbT3wWpAZQQDBiUHVMVmh1822szA==
-----END NEBULA CERTIFICATE-----
`
rootCA := certificateV1{
details: detailsV1{
name: "nebula root ca",
},
}
rootCA01 := certificateV1{
details: detailsV1{
name: "nebula root ca 01",
},
}
rootCAP256 := certificateV1{
details: detailsV1{
name: "nebula P256 test",
},
}
p, err := NewCAPoolFromPEM([]byte(noNewLines))
require.NoError(t, err)
assert.Equal(t, p.CAs["ce4e6c7a596996eb0d82a8875f0f0137a4b53ce22d2421c9fd7150e7a26f6300"].Certificate.Name(), rootCA.details.name)
assert.Equal(t, p.CAs["04c585fcd9a49b276df956a22b7ebea3bf23f1fca5a17c0b56ce2e626631969e"].Certificate.Name(), rootCA01.details.name)
pp, err := NewCAPoolFromPEM([]byte(withNewLines))
require.NoError(t, err)
assert.Equal(t, pp.CAs["ce4e6c7a596996eb0d82a8875f0f0137a4b53ce22d2421c9fd7150e7a26f6300"].Certificate.Name(), rootCA.details.name)
assert.Equal(t, pp.CAs["04c585fcd9a49b276df956a22b7ebea3bf23f1fca5a17c0b56ce2e626631969e"].Certificate.Name(), rootCA01.details.name)
// expired cert, no valid certs
ppp, err := NewCAPoolFromPEM([]byte(expired))
assert.Equal(t, ErrExpired, err)
assert.Equal(t, "expired", ppp.CAs["c39b35a0e8f246203fe4f32b9aa8bfd155f1ae6a6be9d78370641e43397f48f5"].Certificate.Name())
// expired cert, with valid certs
pppp, err := NewCAPoolFromPEM(append([]byte(expired), noNewLines...))
assert.Equal(t, ErrExpired, err)
assert.Equal(t, pppp.CAs["ce4e6c7a596996eb0d82a8875f0f0137a4b53ce22d2421c9fd7150e7a26f6300"].Certificate.Name(), rootCA.details.name)
assert.Equal(t, pppp.CAs["04c585fcd9a49b276df956a22b7ebea3bf23f1fca5a17c0b56ce2e626631969e"].Certificate.Name(), rootCA01.details.name)
assert.Equal(t, "expired", pppp.CAs["c39b35a0e8f246203fe4f32b9aa8bfd155f1ae6a6be9d78370641e43397f48f5"].Certificate.Name())
assert.Len(t, pppp.CAs, 3)
ppppp, err := NewCAPoolFromPEM([]byte(p256))
require.NoError(t, err)
assert.Equal(t, ppppp.CAs["552bf7d99bec1fc775a0e4c324bf6d8f789b3078f1919c7960d2e5e0c351ee97"].Certificate.Name(), rootCAP256.details.name)
assert.Len(t, ppppp.CAs, 1)
}
func TestCertificateV1_Verify(t *testing.T) {
ca, _, caKey, _ := NewTestCaCert(Version1, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, nil)
c, _, _, _ := NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test cert", time.Now(), time.Now().Add(5*time.Minute), nil, nil, nil)
caPool := NewCAPool()
require.NoError(t, caPool.AddCA(ca))
f, err := c.Fingerprint()
require.NoError(t, err)
caPool.BlocklistFingerprint(f)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.EqualError(t, err, "certificate is in the block list")
caPool.ResetCertBlocklist()
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now().Add(time.Hour*1000), c)
require.EqualError(t, err, "root certificate is expired")
assert.PanicsWithError(t, "certificate is valid before the signing certificate", func() {
NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test cert2", time.Time{}, time.Time{}, nil, nil, nil)
})
// Test group assertion
ca, _, caKey, _ = NewTestCaCert(Version1, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{"test1", "test2"})
caPem, err := ca.MarshalPEM()
require.NoError(t, err)
caPool = NewCAPool()
b, err := caPool.AddCAFromPEM(caPem)
require.NoError(t, err)
assert.Empty(t, b)
assert.PanicsWithError(t, "certificate contained a group not present on the signing ca: bad", func() {
NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1", "bad"})
})
c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test2", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
}
func TestCertificateV1_VerifyP256(t *testing.T) {
ca, _, caKey, _ := NewTestCaCert(Version1, Curve_P256, time.Now(), time.Now().Add(10*time.Minute), nil, nil, nil)
c, _, _, _ := NewTestCert(Version1, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, nil)
caPool := NewCAPool()
require.NoError(t, caPool.AddCA(ca))
f, err := c.Fingerprint()
require.NoError(t, err)
caPool.BlocklistFingerprint(f)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.EqualError(t, err, "certificate is in the block list")
// Create a copy of the cert and swap to the alternate form for the signature
nc := c.Copy()
b, err := p256.Swap(c.Signature())
require.NoError(t, err)
require.NoError(t, nc.(*certificateV1).setSignature(b))
_, err = caPool.VerifyCertificate(time.Now(), nc)
require.EqualError(t, err, "certificate is in the block list")
caPool.ResetCertBlocklist()
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now().Add(time.Hour*1000), c)
require.EqualError(t, err, "root certificate is expired")
assert.PanicsWithError(t, "certificate is valid before the signing certificate", func() {
NewTestCert(Version1, Curve_P256, ca, caKey, "test", time.Time{}, time.Time{}, nil, nil, nil)
})
// Test group assertion
ca, _, caKey, _ = NewTestCaCert(Version1, Curve_P256, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{"test1", "test2"})
caPem, err := ca.MarshalPEM()
require.NoError(t, err)
caPool = NewCAPool()
b, err = caPool.AddCAFromPEM(caPem)
require.NoError(t, err)
assert.Empty(t, b)
assert.PanicsWithError(t, "certificate contained a group not present on the signing ca: bad", func() {
NewTestCert(Version1, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1", "bad"})
})
c, _, _, _ = NewTestCert(Version1, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1"})
cc, err := caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Reset the blocklist and block the alternate form fingerprint
caPool.ResetCertBlocklist()
caPool.BlocklistFingerprint(cc.fingerprint2)
err = caPool.VerifyCachedCertificate(time.Now(), cc)
require.EqualError(t, err, "certificate is in the block list")
caPool.ResetCertBlocklist()
err = caPool.VerifyCachedCertificate(time.Now(), cc)
require.NoError(t, err)
}
func TestCertificateV1_Verify_IPs(t *testing.T) {
caIp1 := mustParsePrefixUnmapped("10.0.0.0/16")
caIp2 := mustParsePrefixUnmapped("192.168.0.0/24")
ca, _, caKey, _ := NewTestCaCert(Version1, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), []netip.Prefix{caIp1, caIp2}, nil, []string{"test"})
caPem, err := ca.MarshalPEM()
require.NoError(t, err)
caPool := NewCAPool()
b, err := caPool.AddCAFromPEM(caPem)
require.NoError(t, err)
assert.Empty(t, b)
// ip is outside the network
cIp1 := mustParsePrefixUnmapped("10.1.0.0/24")
cIp2 := mustParsePrefixUnmapped("192.168.0.1/16")
assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
})
// ip is outside the network reversed order of above
cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
cIp2 = mustParsePrefixUnmapped("10.1.0.0/24")
assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
})
// ip is within the network but mask is outside
cIp1 = mustParsePrefixUnmapped("10.0.1.0/15")
cIp2 = mustParsePrefixUnmapped("192.168.0.1/24")
assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
})
// ip is within the network but mask is outside reversed order of above
cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
cIp2 = mustParsePrefixUnmapped("10.0.1.0/15")
assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
})
// ip and mask are within the network
cIp1 = mustParsePrefixUnmapped("10.0.1.0/16")
cIp2 = mustParsePrefixUnmapped("192.168.0.1/25")
c, _, _, _ := NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches
c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp1, caIp2}, nil, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches reversed
c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp2, caIp1}, nil, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches reversed with just 1
c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp1}, nil, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
}
func TestCertificateV1_Verify_Subnets(t *testing.T) {
caIp1 := mustParsePrefixUnmapped("10.0.0.0/16")
caIp2 := mustParsePrefixUnmapped("192.168.0.0/24")
ca, _, caKey, _ := NewTestCaCert(Version1, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, []netip.Prefix{caIp1, caIp2}, []string{"test"})
caPem, err := ca.MarshalPEM()
require.NoError(t, err)
caPool := NewCAPool()
b, err := caPool.AddCAFromPEM(caPem)
require.NoError(t, err)
assert.Empty(t, b)
// ip is outside the network
cIp1 := mustParsePrefixUnmapped("10.1.0.0/24")
cIp2 := mustParsePrefixUnmapped("192.168.0.1/16")
assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
})
// ip is outside the network reversed order of above
cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
cIp2 = mustParsePrefixUnmapped("10.1.0.0/24")
assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
})
// ip is within the network but mask is outside
cIp1 = mustParsePrefixUnmapped("10.0.1.0/15")
cIp2 = mustParsePrefixUnmapped("192.168.0.1/24")
assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
})
// ip is within the network but mask is outside reversed order of above
cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
cIp2 = mustParsePrefixUnmapped("10.0.1.0/15")
assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
})
// ip and mask are within the network
cIp1 = mustParsePrefixUnmapped("10.0.1.0/16")
cIp2 = mustParsePrefixUnmapped("192.168.0.1/25")
c, _, _, _ := NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches
c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp1, caIp2}, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches reversed
c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp2, caIp1}, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches reversed with just 1
c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp1}, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
}
func TestCertificateV2_Verify(t *testing.T) {
ca, _, caKey, _ := NewTestCaCert(Version2, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, nil)
c, _, _, _ := NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test cert", time.Now(), time.Now().Add(5*time.Minute), nil, nil, nil)
caPool := NewCAPool()
require.NoError(t, caPool.AddCA(ca))
f, err := c.Fingerprint()
require.NoError(t, err)
caPool.BlocklistFingerprint(f)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.EqualError(t, err, "certificate is in the block list")
caPool.ResetCertBlocklist()
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now().Add(time.Hour*1000), c)
require.EqualError(t, err, "root certificate is expired")
assert.PanicsWithError(t, "certificate is valid before the signing certificate", func() {
NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test cert2", time.Time{}, time.Time{}, nil, nil, nil)
})
// Test group assertion
ca, _, caKey, _ = NewTestCaCert(Version2, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{"test1", "test2"})
caPem, err := ca.MarshalPEM()
require.NoError(t, err)
caPool = NewCAPool()
b, err := caPool.AddCAFromPEM(caPem)
require.NoError(t, err)
assert.Empty(t, b)
assert.PanicsWithError(t, "certificate contained a group not present on the signing ca: bad", func() {
NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1", "bad"})
})
c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test2", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
}
func TestCertificateV2_VerifyP256(t *testing.T) {
ca, _, caKey, _ := NewTestCaCert(Version2, Curve_P256, time.Now(), time.Now().Add(10*time.Minute), nil, nil, nil)
c, _, _, _ := NewTestCert(Version2, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, nil)
caPool := NewCAPool()
require.NoError(t, caPool.AddCA(ca))
f, err := c.Fingerprint()
require.NoError(t, err)
caPool.BlocklistFingerprint(f)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.EqualError(t, err, "certificate is in the block list")
// Create a copy of the cert and swap to the alternate form for the signature
nc := c.Copy()
b, err := p256.Swap(c.Signature())
require.NoError(t, err)
require.NoError(t, nc.(*certificateV2).setSignature(b))
_, err = caPool.VerifyCertificate(time.Now(), nc)
require.EqualError(t, err, "certificate is in the block list")
caPool.ResetCertBlocklist()
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now().Add(time.Hour*1000), c)
require.EqualError(t, err, "root certificate is expired")
assert.PanicsWithError(t, "certificate is valid before the signing certificate", func() {
NewTestCert(Version2, Curve_P256, ca, caKey, "test", time.Time{}, time.Time{}, nil, nil, nil)
})
// Test group assertion
ca, _, caKey, _ = NewTestCaCert(Version2, Curve_P256, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{"test1", "test2"})
caPem, err := ca.MarshalPEM()
require.NoError(t, err)
caPool = NewCAPool()
b, err = caPool.AddCAFromPEM(caPem)
require.NoError(t, err)
assert.Empty(t, b)
assert.PanicsWithError(t, "certificate contained a group not present on the signing ca: bad", func() {
NewTestCert(Version2, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1", "bad"})
})
c, _, _, _ = NewTestCert(Version2, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1"})
cc, err := caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Reset the blocklist and block the alternate form fingerprint
caPool.ResetCertBlocklist()
caPool.BlocklistFingerprint(cc.fingerprint2)
err = caPool.VerifyCachedCertificate(time.Now(), cc)
require.EqualError(t, err, "certificate is in the block list")
caPool.ResetCertBlocklist()
err = caPool.VerifyCachedCertificate(time.Now(), cc)
require.NoError(t, err)
}
func TestCertificateV2_Verify_IPs(t *testing.T) {
caIp1 := mustParsePrefixUnmapped("10.0.0.0/16")
caIp2 := mustParsePrefixUnmapped("192.168.0.0/24")
ca, _, caKey, _ := NewTestCaCert(Version2, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), []netip.Prefix{caIp1, caIp2}, nil, []string{"test"})
caPem, err := ca.MarshalPEM()
require.NoError(t, err)
caPool := NewCAPool()
b, err := caPool.AddCAFromPEM(caPem)
require.NoError(t, err)
assert.Empty(t, b)
// ip is outside the network
cIp1 := mustParsePrefixUnmapped("10.1.0.0/24")
cIp2 := mustParsePrefixUnmapped("192.168.0.1/16")
assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
})
// ip is outside the network reversed order of above
cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
cIp2 = mustParsePrefixUnmapped("10.1.0.0/24")
assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
})
// ip is within the network but mask is outside
cIp1 = mustParsePrefixUnmapped("10.0.1.0/15")
cIp2 = mustParsePrefixUnmapped("192.168.0.1/24")
assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
})
// ip is within the network but mask is outside reversed order of above
cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
cIp2 = mustParsePrefixUnmapped("10.0.1.0/15")
assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
})
// ip and mask are within the network
cIp1 = mustParsePrefixUnmapped("10.0.1.0/16")
cIp2 = mustParsePrefixUnmapped("192.168.0.1/25")
c, _, _, _ := NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches
c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp1, caIp2}, nil, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches reversed
c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp2, caIp1}, nil, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches reversed with just 1
c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp1}, nil, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
}
func TestCertificateV2_Verify_Subnets(t *testing.T) {
caIp1 := mustParsePrefixUnmapped("10.0.0.0/16")
caIp2 := mustParsePrefixUnmapped("192.168.0.0/24")
ca, _, caKey, _ := NewTestCaCert(Version2, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, []netip.Prefix{caIp1, caIp2}, []string{"test"})
caPem, err := ca.MarshalPEM()
require.NoError(t, err)
caPool := NewCAPool()
b, err := caPool.AddCAFromPEM(caPem)
require.NoError(t, err)
assert.Empty(t, b)
// ip is outside the network
cIp1 := mustParsePrefixUnmapped("10.1.0.0/24")
cIp2 := mustParsePrefixUnmapped("192.168.0.1/16")
assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
})
// ip is outside the network reversed order of above
cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
cIp2 = mustParsePrefixUnmapped("10.1.0.0/24")
assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
})
// ip is within the network but mask is outside
cIp1 = mustParsePrefixUnmapped("10.0.1.0/15")
cIp2 = mustParsePrefixUnmapped("192.168.0.1/24")
assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
})
// ip is within the network but mask is outside reversed order of above
cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
cIp2 = mustParsePrefixUnmapped("10.0.1.0/15")
assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
})
// ip and mask are within the network
cIp1 = mustParsePrefixUnmapped("10.0.1.0/16")
cIp2 = mustParsePrefixUnmapped("192.168.0.1/25")
c, _, _, _ := NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches
c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp1, caIp2}, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches reversed
c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp2, caIp1}, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
// Exact matches reversed with just 1
c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp1}, []string{"test"})
require.NoError(t, err)
_, err = caPool.VerifyCertificate(time.Now(), c)
require.NoError(t, err)
}
================================================
FILE: cert/cert.go
================================================
package cert
import (
"fmt"
"net/netip"
"time"
"github.com/slackhq/nebula/cert/p256"
)
type Version uint8
const (
VersionPre1 Version = 0
Version1 Version = 1
Version2 Version = 2
)
type Certificate interface {
// Version defines the underlying certificate structure and wire protocol version
// Version1 certificates are ipv4 only and uses protobuf serialization
// Version2 certificates are ipv4 or ipv6 and uses asn.1 serialization
Version() Version
// Name is the human-readable name that identifies this certificate.
Name() string
// Networks is a list of ip addresses and network sizes assigned to this certificate.
// If IsCA is true then certificates signed by this CA can only have ip addresses and
// networks that are contained by an entry in this list.
Networks() []netip.Prefix
// UnsafeNetworks is a list of networks that this host can act as an unsafe router for.
// If IsCA is true then certificates signed by this CA can only have networks that are
// contained by an entry in this list.
UnsafeNetworks() []netip.Prefix
// Groups is a list of identities that can be used to write more general firewall rule
// definitions.
// If IsCA is true then certificates signed by this CA can only use groups that are
// in this list.
Groups() []string
// IsCA signifies if this is a certificate authority (true) or a host certificate (false).
// It is invalid to use a CA certificate as a host certificate.
IsCA() bool
// NotBefore is the time at which this certificate becomes valid.
// If IsCA is true then certificate signed by this CA can not have a time before this.
NotBefore() time.Time
// NotAfter is the time at which this certificate becomes invalid.
// If IsCA is true then certificate signed by this CA can not have a time after this.
NotAfter() time.Time
// Issuer is the fingerprint of the CA that signed this certificate.
// If IsCA is true then this will be empty.
Issuer() string
// PublicKey is the raw bytes to be used in asymmetric cryptographic operations.
PublicKey() []byte
// MarshalPublicKeyPEM is the value of PublicKey marshalled to PEM
MarshalPublicKeyPEM() []byte
// Curve identifies which curve was used for the PublicKey and Signature.
Curve() Curve
// Signature is the cryptographic seal for all the details of this certificate.
// CheckSignature can be used to verify that the details of this certificate are valid.
Signature() []byte
// CheckSignature will check that the certificate Signature() matches the
// computed signature. A true result means this certificate has not been tampered with.
CheckSignature(signingPublicKey []byte) bool
// Fingerprint returns the hex encoded sha256 sum of the certificate.
// This acts as a unique fingerprint and can be used to blocklist certificates.
Fingerprint() (string, error)
// Expired tests if the certificate is valid for the provided time.
Expired(t time.Time) bool
// VerifyPrivateKey returns an error if the private key is not a pair with the certificates public key.
VerifyPrivateKey(curve Curve, privateKey []byte) error
// Marshal will return the byte representation of this certificate
// This is primarily the format transmitted on the wire.
Marshal() ([]byte, error)
// MarshalForHandshakes prepares the bytes needed to use directly in a handshake
MarshalForHandshakes() ([]byte, error)
// MarshalPEM will return a PEM encoded representation of this certificate
// This is primarily the format stored on disk
MarshalPEM() ([]byte, error)
// MarshalJSON will return the json representation of this certificate
MarshalJSON() ([]byte, error)
// String will return a human-readable representation of this certificate
String() string
// Copy creates a copy of the certificate
Copy() Certificate
}
// CachedCertificate represents a verified certificate with some cached fields to improve
// performance.
type CachedCertificate struct {
Certificate Certificate
InvertedGroups map[string]struct{}
Fingerprint string
signerFingerprint string
// A place to store a 2nd fingerprint if the certificate could have one, such as with P256
fingerprint2 string
}
func (cc *CachedCertificate) String() string {
return cc.Certificate.String()
}
// Recombine will attempt to unmarshal a certificate received in a handshake.
// Handshakes save space by placing the peers public key in a different part of the packet, we have to
// reassemble the actual certificate structure with that in mind.
// Implementations MUST assert the public key is not in the raw certificate bytes if the passed in public key is not empty.
func Recombine(v Version, rawCertBytes, publicKey []byte, curve Curve) (Certificate, error) {
if publicKey == nil {
return nil, ErrNoPeerStaticKey
}
if rawCertBytes == nil {
return nil, ErrNoPayload
}
var c Certificate
var err error
switch v {
// Implementations must ensure the result is a valid cert!
case VersionPre1, Version1:
c, err = unmarshalCertificateV1(rawCertBytes, publicKey)
case Version2:
c, err = unmarshalCertificateV2(rawCertBytes, publicKey, curve)
default:
return nil, ErrUnknownVersion
}
if err != nil {
return nil, err
}
if c.Curve() != curve {
return nil, fmt.Errorf("certificate curve %s does not match expected %s", c.Curve().String(), curve.String())
}
return c, nil
}
// CalculateAlternateFingerprint calculates a 2nd fingerprint representation for P256 certificates
// CAPool blocklist testing through `VerifyCertificate` and `VerifyCachedCertificate` automatically performs this step.
func CalculateAlternateFingerprint(c Certificate) (string, error) {
if c.Curve() != Curve_P256 {
return "", nil
}
nc := c.Copy()
b, err := p256.Swap(nc.Signature())
if err != nil {
return "", err
}
switch v := nc.(type) {
case *certificateV1:
err = v.setSignature(b)
case *certificateV2:
err = v.setSignature(b)
default:
return "", ErrUnknownVersion
}
if err != nil {
return "", err
}
return nc.Fingerprint()
}
================================================
FILE: cert/cert_v1.go
================================================
package cert
import (
"bytes"
"crypto/ecdh"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"encoding/json"
"encoding/pem"
"fmt"
"net"
"net/netip"
"time"
"golang.org/x/crypto/curve25519"
"google.golang.org/protobuf/proto"
)
const publicKeyLen = 32
type certificateV1 struct {
details detailsV1
signature []byte
}
type detailsV1 struct {
name string
networks []netip.Prefix
unsafeNetworks []netip.Prefix
groups []string
notBefore time.Time
notAfter time.Time
publicKey []byte
isCA bool
issuer string
curve Curve
}
type m = map[string]any
func (c *certificateV1) Version() Version {
return Version1
}
func (c *certificateV1) Curve() Curve {
return c.details.curve
}
func (c *certificateV1) Groups() []string {
return c.details.groups
}
func (c *certificateV1) IsCA() bool {
return c.details.isCA
}
func (c *certificateV1) Issuer() string {
return c.details.issuer
}
func (c *certificateV1) Name() string {
return c.details.name
}
func (c *certificateV1) Networks() []netip.Prefix {
return c.details.networks
}
func (c *certificateV1) NotAfter() time.Time {
return c.details.notAfter
}
func (c *certificateV1) NotBefore() time.Time {
return c.details.notBefore
}
func (c *certificateV1) PublicKey() []byte {
return c.details.publicKey
}
func (c *certificateV1) MarshalPublicKeyPEM() []byte {
return marshalCertPublicKeyToPEM(c)
}
func (c *certificateV1) Signature() []byte {
return c.signature
}
func (c *certificateV1) UnsafeNetworks() []netip.Prefix {
return c.details.unsafeNetworks
}
func (c *certificateV1) Fingerprint() (string, error) {
b, err := c.Marshal()
if err != nil {
return "", err
}
sum := sha256.Sum256(b)
return hex.EncodeToString(sum[:]), nil
}
func (c *certificateV1) CheckSignature(key []byte) bool {
b, err := proto.Marshal(c.getRawDetails())
if err != nil {
return false
}
switch c.details.curve {
case Curve_CURVE25519:
return ed25519.Verify(key, b, c.signature)
case Curve_P256:
pubKey, err := ecdsa.ParseUncompressedPublicKey(elliptic.P256(), key)
if err != nil {
return false
}
hashed := sha256.Sum256(b)
return ecdsa.VerifyASN1(pubKey, hashed[:], c.signature)
default:
return false
}
}
func (c *certificateV1) Expired(t time.Time) bool {
return c.details.notBefore.After(t) || c.details.notAfter.Before(t)
}
func (c *certificateV1) VerifyPrivateKey(curve Curve, key []byte) error {
if curve != c.details.curve {
return fmt.Errorf("curve in cert and private key supplied don't match")
}
if c.details.isCA {
switch curve {
case Curve_CURVE25519:
// the call to PublicKey below will panic slice bounds out of range otherwise
if len(key) != ed25519.PrivateKeySize {
return fmt.Errorf("key was not 64 bytes, is invalid ed25519 private key")
}
if !ed25519.PublicKey(c.details.publicKey).Equal(ed25519.PrivateKey(key).Public()) {
return fmt.Errorf("public key in cert and private key supplied don't match")
}
case Curve_P256:
privkey, err := ecdh.P256().NewPrivateKey(key)
if err != nil {
return fmt.Errorf("cannot parse private key as P256: %w", err)
}
pub := privkey.PublicKey().Bytes()
if !bytes.Equal(pub, c.details.publicKey) {
return fmt.Errorf("public key in cert and private key supplied don't match")
}
default:
return fmt.Errorf("invalid curve: %s", curve)
}
return nil
}
var pub []byte
switch curve {
case Curve_CURVE25519:
var err error
pub, err = curve25519.X25519(key, curve25519.Basepoint)
if err != nil {
return err
}
case Curve_P256:
privkey, err := ecdh.P256().NewPrivateKey(key)
if err != nil {
return err
}
pub = privkey.PublicKey().Bytes()
default:
return fmt.Errorf("invalid curve: %s", curve)
}
if !bytes.Equal(pub, c.details.publicKey) {
return fmt.Errorf("public key in cert and private key supplied don't match")
}
return nil
}
// getRawDetails marshals the raw details into protobuf ready struct
func (c *certificateV1) getRawDetails() *RawNebulaCertificateDetails {
rd := &RawNebulaCertificateDetails{
Name: c.details.name,
Groups: c.details.groups,
NotBefore: c.details.notBefore.Unix(),
NotAfter: c.details.notAfter.Unix(),
PublicKey: make([]byte, len(c.details.publicKey)),
IsCA: c.details.isCA,
Curve: c.details.curve,
}
for _, ipNet := range c.details.networks {
mask := net.CIDRMask(ipNet.Bits(), ipNet.Addr().BitLen())
rd.Ips = append(rd.Ips, addr2int(ipNet.Addr()), ip2int(mask))
}
for _, ipNet := range c.details.unsafeNetworks {
mask := net.CIDRMask(ipNet.Bits(), ipNet.Addr().BitLen())
rd.Subnets = append(rd.Subnets, addr2int(ipNet.Addr()), ip2int(mask))
}
copy(rd.PublicKey, c.details.publicKey[:])
// I know, this is terrible
rd.Issuer, _ = hex.DecodeString(c.details.issuer)
return rd
}
func (c *certificateV1) String() string {
b, err := json.MarshalIndent(c.marshalJSON(), "", "\t")
if err != nil {
return fmt.Sprintf("<error marshalling certificate: %v>", err)
}
return string(b)
}
func (c *certificateV1) MarshalForHandshakes() ([]byte, error) {
pubKey := c.details.publicKey
c.details.publicKey = nil
rawCertNoKey, err := c.Marshal()
if err != nil {
return nil, err
}
c.details.publicKey = pubKey
return rawCertNoKey, nil
}
func (c *certificateV1) Marshal() ([]byte, error) {
rc := RawNebulaCertificate{
Details: c.getRawDetails(),
Signature: c.signature,
}
return proto.Marshal(&rc)
}
func (c *certificateV1) MarshalPEM() ([]byte, error) {
b, err := c.Marshal()
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{Type: CertificateBanner, Bytes: b}), nil
}
func (c *certificateV1) MarshalJSON() ([]byte, error) {
return json.Marshal(c.marshalJSON())
}
func (c *certificateV1) marshalJSON() m {
fp, _ := c.Fingerprint()
return m{
"version": Version1,
"details": m{
"name": c.details.name,
"networks": c.details.networks,
"unsafeNetworks": c.details.unsafeNetworks,
"groups": c.details.groups,
"notBefore": c.details.notBefore,
"notAfter": c.details.notAfter,
"publicKey": fmt.Sprintf("%x", c.details.publicKey),
"isCa": c.details.isCA,
"issuer": c.details.issuer,
"curve": c.details.curve.String(),
},
"fingerprint": fp,
"signature": fmt.Sprintf("%x", c.Signature()),
}
}
func (c *certificateV1) Copy() Certificate {
nc := &certificateV1{
details: detailsV1{
name: c.details.name,
notBefore: c.details.notBefore,
notAfter: c.details.notAfter,
publicKey: make([]byte, len(c.details.publicKey)),
isCA: c.details.isCA,
issuer: c.details.issuer,
curve: c.details.curve,
},
signature: make([]byte, len(c.signature)),
}
if c.details.groups != nil {
nc.details.groups = make([]string, len(c.details.groups))
copy(nc.details.groups, c.details.groups)
}
if c.details.networks != nil {
nc.details.networks = make([]netip.Prefix, len(c.details.networks))
copy(nc.details.networks, c.details.networks)
}
if c.details.unsafeNetworks != nil {
nc.details.unsafeNetworks = make([]netip.Prefix, len(c.details.unsafeNetworks))
copy(nc.details.unsafeNetworks, c.details.unsafeNetworks)
}
copy(nc.signature, c.signature)
copy(nc.details.publicKey, c.details.publicKey)
return nc
}
func (c *certificateV1) fromTBSCertificate(t *TBSCertificate) error {
c.details = detailsV1{
name: t.Name,
networks: t.Networks,
unsafeNetworks: t.UnsafeNetworks,
groups: t.Groups,
notBefore: t.NotBefore,
notAfter: t.NotAfter,
publicKey: t.PublicKey,
isCA: t.IsCA,
curve: t.Curve,
issuer: t.issuer,
}
return c.validate()
}
func (c *certificateV1) validate() error {
// Empty names are allowed
if len(c.details.publicKey) == 0 {
return ErrInvalidPublicKey
}
// Original v1 rules allowed multiple networks to be present but ignored all but the first one.
// Continue to allow this behavior
if !c.details.isCA && len(c.details.networks) == 0 {
return NewErrInvalidCertificateProperties("non-CA certificates must contain exactly one network")
}
for _, network := range c.details.networks {
if !network.IsValid() || !network.Addr().IsValid() {
return NewErrInvalidCertificateProperties("invalid network: %s", network)
}
if network.Addr().Is6() {
return NewErrInvalidCertificateProperties("certificate may not contain IPv6 networks: %v", network)
}
if network.Addr().IsUnspecified() {
return NewErrInvalidCertificateProperties("non-CA certificates must not use the zero address as a network: %s", network)
}
if network.Addr().Zone() != "" {
return NewErrInvalidCertificateProperties("networks may not contain zones: %s", network)
}
}
for _, network := range c.details.unsafeNetworks {
if !network.IsValid() || !network.Addr().IsValid() {
return NewErrInvalidCertificateProperties("invalid unsafe network: %s", network)
}
if network.Addr().Is6() {
return NewErrInvalidCertificateProperties("certificate may not contain IPv6 unsafe networks: %v", network)
}
if network.Addr().Zone() != "" {
return NewErrInvalidCertificateProperties("unsafe networks may not contain zones: %s", network)
}
}
// v1 doesn't bother with sort order or uniqueness of networks or unsafe networks.
// We can't modify the unmarshalled data because verification requires re-marshalling and a re-ordered
// unsafe networks would result in a different signature.
return nil
}
func (c *certificateV1) marshalForSigning() ([]byte, error) {
b, err := proto.Marshal(c.getRawDetails())
if err != nil {
return nil, err
}
return b, nil
}
func (c *certificateV1) setSignature(b []byte) error {
if len(b) == 0 {
return ErrEmptySignature
}
c.signature = b
return nil
}
// unmarshalCertificateV1 will unmarshal a protobuf byte representation of a nebula cert
// if the publicKey is provided here then it is not required to be present in `b`
func unmarshalCertificateV1(b []byte, publicKey []byte) (*certificateV1, error) {
if len(b) == 0 {
return nil, fmt.Errorf("nil byte array")
}
var rc RawNebulaCertificate
err := proto.Unmarshal(b, &rc)
if err != nil {
return nil, err
}
if rc.Details == nil {
return nil, fmt.Errorf("encoded Details was nil")
}
if len(rc.Details.Ips)%2 != 0 {
return nil, fmt.Errorf("encoded IPs should be in pairs, an odd number was found")
}
if len(rc.Details.Subnets)%2 != 0 {
return nil, fmt.Errorf("encoded Subnets should be in pairs, an odd number was found")
}
nc := certificateV1{
details: detailsV1{
name: rc.Details.Name,
groups: make([]string, len(rc.Details.Groups)),
networks: make([]netip.Prefix, len(rc.Details.Ips)/2),
unsafeNetworks: make([]netip.Prefix, len(rc.Details.Subnets)/2),
notBefore: time.Unix(rc.Details.NotBefore, 0),
notAfter: time.Unix(rc.Details.NotAfter, 0),
publicKey: nil,
isCA: rc.Details.IsCA,
curve: rc.Details.Curve,
},
signature: make([]byte, len(rc.Signature)),
}
copy(nc.signature, rc.Signature)
copy(nc.details.groups, rc.Details.Groups)
nc.details.issuer = hex.EncodeToString(rc.Details.Issuer)
// If a public key is passed in as an argument, the certificate pubkey must be empty
// and the passed-in pubkey copied into the cert.
if len(publicKey) > 0 {
if len(rc.Details.PublicKey) != 0 {
return nil, ErrCertPubkeyPresent
}
nc.details.publicKey = make([]byte, len(publicKey))
copy(nc.details.publicKey, publicKey)
} else {
nc.details.publicKey = make([]byte, len(rc.Details.PublicKey))
copy(nc.details.publicKey, rc.Details.PublicKey)
}
var ip netip.Addr
for i, rawIp := range rc.Details.Ips {
if i%2 == 0 {
ip = int2addr(rawIp)
} else {
ones, _ := net.IPMask(int2ip(rawIp)).Size()
nc.details.networks[i/2] = netip.PrefixFrom(ip, ones)
}
}
for i, rawIp := range rc.Details.Subnets {
if i%2 == 0 {
ip = int2addr(rawIp)
} else {
ones, _ := net.IPMask(int2ip(rawIp)).Size()
nc.details.unsafeNetworks[i/2] = netip.PrefixFrom(ip, ones)
}
}
err = nc.validate()
if err != nil {
return nil, err
}
return &nc, nil
}
func ip2int(ip []byte) uint32 {
if len(ip) == 16 {
return binary.BigEndian.Uint32(ip[12:16])
}
return binary.BigEndian.Uint32(ip)
}
func int2ip(nn uint32) net.IP {
ip := make(net.IP, net.IPv4len)
binary.BigEndian.PutUint32(ip, nn)
return ip
}
func addr2int(addr netip.Addr) uint32 {
b := addr.Unmap().As4()
return binary.BigEndian.Uint32(b[:])
}
func int2addr(nn uint32) netip.Addr {
ip := [4]byte{}
binary.BigEndian.PutUint32(ip[:], nn)
return netip.AddrFrom4(ip).Unmap()
}
================================================
FILE: cert/cert_v1.pb.go
================================================
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc v3.21.5
// source: cert_v1.proto
package cert
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Curve int32
const (
Curve_CURVE25519 Curve = 0
Curve_P256 Curve = 1
)
// Enum value maps for Curve.
var (
Curve_name = map[int32]string{
0: "CURVE25519",
1: "P256",
}
Curve_value = map[string]int32{
"CURVE25519": 0,
"P256": 1,
}
)
func (x Curve) Enum() *Curve {
p := new(Curve)
*p = x
return p
}
func (x Curve) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Curve) Descriptor() protoreflect.EnumDescriptor {
return file_cert_v1_proto_enumTypes[0].Descriptor()
}
func (Curve) Type() protoreflect.EnumType {
return &file_cert_v1_proto_enumTypes[0]
}
func (x Curve) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Curve.Descriptor instead.
func (Curve) EnumDescriptor() ([]byte, []int) {
return file_cert_v1_proto_rawDescGZIP(), []int{0}
}
type RawNebulaCertificate struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Details *RawNebulaCertificateDetails `protobuf:"bytes,1,opt,name=Details,proto3" json:"Details,omitempty"`
Signature []byte `protobuf:"bytes,2,opt,name=Signature,proto3" json:"Signature,omitempty"`
}
func (x *RawNebulaCertificate) Reset() {
*x = RawNebulaCertificate{}
if protoimpl.UnsafeEnabled {
mi := &file_cert_v1_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RawNebulaCertificate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RawNebulaCertificate) ProtoMessage() {}
func (x *RawNebulaCertificate) ProtoReflect() protoreflect.Message {
mi := &file_cert_v1_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RawNebulaCertificate.ProtoReflect.Descriptor instead.
func (*RawNebulaCertificate) Descriptor() ([]byte, []int) {
return file_cert_v1_proto_rawDescGZIP(), []int{0}
}
func (x *RawNebulaCertificate) GetDetails() *RawNebulaCertificateDetails {
if x != nil {
return x.Details
}
return nil
}
func (x *RawNebulaCertificate) GetSignature() []byte {
if x != nil {
return x.Signature
}
return nil
}
type RawNebulaCertificateDetails struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
// Ips and Subnets are in big endian 32 bit pairs, 1st the ip, 2nd the mask
Ips []uint32 `protobuf:"varint,2,rep,packed,name=Ips,proto3" json:"Ips,omitempty"`
Subnets []uint32 `protobuf:"varint,3,rep,packed,name=Subnets,proto3" json:"Subnets,omitempty"`
Groups []string `protobuf:"bytes,4,rep,name=Groups,proto3" json:"Groups,omitempty"`
NotBefore int64 `protobuf:"varint,5,opt,name=NotBefore,proto3" json:"NotBefore,omitempty"`
NotAfter int64 `protobuf:"varint,6,opt,name=NotAfter,proto3" json:"NotAfter,omitempty"`
PublicKey []byte `protobuf:"bytes,7,opt,name=PublicKey,proto3" json:"PublicKey,omitempty"`
IsCA bool `protobuf:"varint,8,opt,name=IsCA,proto3" json:"IsCA,omitempty"`
// sha-256 of the issuer certificate, if this field is blank the cert is self-signed
Issuer []byte `protobuf:"bytes,9,opt,name=Issuer,proto3" json:"Issuer,omitempty"`
Curve Curve `protobuf:"varint,100,opt,name=curve,proto3,enum=cert.Curve" json:"curve,omitempty"`
}
func (x *RawNebulaCertificateDetails) Reset() {
*x = RawNebulaCertificateDetails{}
if protoimpl.UnsafeEnabled {
mi := &file_cert_v1_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RawNebulaCertificateDetails) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RawNebulaCertificateDetails) ProtoMessage() {}
func (x *RawNebulaCertificateDetails) ProtoReflect() protoreflect.Message {
mi := &file_cert_v1_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RawNebulaCertificateDetails.ProtoReflect.Descriptor instead.
func (*RawNebulaCertificateDetails) Descriptor() ([]byte, []int) {
return file_cert_v1_proto_rawDescGZIP(), []int{1}
}
func (x *RawNebulaCertificateDetails) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *RawNebulaCertificateDetails) GetIps() []uint32 {
if x != nil {
return x.Ips
}
return nil
}
func (x *RawNebulaCertificateDetails) GetSubnets() []uint32 {
if x != nil {
return x.Subnets
}
return nil
}
func (x *RawNebulaCertificateDetails) GetGroups() []string {
if x != nil {
return x.Groups
}
return nil
}
func (x *RawNebulaCertificateDetails) GetNotBefore() int64 {
if x != nil {
return x.NotBefore
}
return 0
}
func (x *RawNebulaCertificateDetails) GetNotAfter() int64 {
if x != nil {
return x.NotAfter
}
return 0
}
func (x *RawNebulaCertificateDetails) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *RawNebulaCertificateDetails) GetIsCA() bool {
if x != nil {
return x.IsCA
}
return false
}
func (x *RawNebulaCertificateDetails) GetIssuer() []byte {
if x != nil {
return x.Issuer
}
return nil
}
func (x *RawNebulaCertificateDetails) GetCurve() Curve {
if x != nil {
return x.Curve
}
return Curve_CURVE25519
}
type RawNebulaEncryptedData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
EncryptionMetadata *RawNebulaEncryptionMetadata `protobuf:"bytes,1,opt,name=EncryptionMetadata,proto3" json:"EncryptionMetadata,omitempty"`
Ciphertext []byte `protobuf:"bytes,2,opt,name=Ciphertext,proto3" json:"Ciphertext,omitempty"`
}
func (x *RawNebulaEncryptedData) Reset() {
*x = RawNebulaEncryptedData{}
if protoimpl.UnsafeEnabled {
mi := &file_cert_v1_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RawNebulaEncryptedData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RawNebulaEncryptedData) ProtoMessage() {}
func (x *RawNebulaEncryptedData) ProtoReflect() protoreflect.Message {
mi := &file_cert_v1_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RawNebulaEncryptedData.ProtoReflect.Descriptor instead.
func (*RawNebulaEncryptedData) Descriptor() ([]byte, []int) {
return file_cert_v1_proto_rawDescGZIP(), []int{2}
}
func (x *RawNebulaEncryptedData) GetEncryptionMetadata() *RawNebulaEncryptionMetadata {
if x != nil {
return x.EncryptionMetadata
}
return nil
}
func (x *RawNebulaEncryptedData) GetCiphertext() []byte {
if x != nil {
return x.Ciphertext
}
return nil
}
type RawNebulaEncryptionMetadata struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
EncryptionAlgorithm string `protobuf:"bytes,1,opt,name=EncryptionAlgorithm,proto3" json:"EncryptionAlgorithm,omitempty"`
Argon2Parameters *RawNebulaArgon2Parameters `protobuf:"bytes,2,opt,name=Argon2Parameters,proto3" json:"Argon2Parameters,omitempty"`
}
func (x *RawNebulaEncryptionMetadata) Reset() {
*x = RawNebulaEncryptionMetadata{}
if protoimpl.UnsafeEnabled {
mi := &file_cert_v1_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RawNebulaEncryptionMetadata) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RawNebulaEncryptionMetadata) ProtoMessage() {}
func (x *RawNebulaEncryptionMetadata) ProtoReflect() protoreflect.Message {
mi := &file_cert_v1_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RawNebulaEncryptionMetadata.ProtoReflect.Descriptor instead.
func (*RawNebulaEncryptionMetadata) Descriptor() ([]byte, []int) {
return file_cert_v1_proto_rawDescGZIP(), []int{3}
}
func (x *RawNebulaEncryptionMetadata) GetEncryptionAlgorithm() string {
if x != nil {
return x.EncryptionAlgorithm
}
return ""
}
func (x *RawNebulaEncryptionMetadata) GetArgon2Parameters() *RawNebulaArgon2Parameters {
if x != nil {
return x.Argon2Parameters
}
return nil
}
type RawNebulaArgon2Parameters struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` // rune in Go
Memory uint32 `protobuf:"varint,2,opt,name=memory,proto3" json:"memory,omitempty"`
Parallelism uint32 `protobuf:"varint,4,opt,name=parallelism,proto3" json:"parallelism,omitempty"` // uint8 in Go
Iterations uint32 `protobuf:"varint,3,opt,name=iterations,proto3" json:"iterations,omitempty"`
Salt []byte `protobuf:"bytes,5,opt,name=salt,proto3" json:"salt,omitempty"`
}
func (x *RawNebulaArgon2Parameters) Reset() {
*x = RawNebulaArgon2Parameters{}
if protoimpl.UnsafeEnabled {
mi := &file_cert_v1_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RawNebulaArgon2Parameters) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RawNebulaArgon2Parameters) ProtoMessage() {}
func (x *RawNebulaArgon2Parameters) ProtoReflect() protoreflect.Message {
mi := &file_cert_v1_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RawNebulaArgon2Parameters.ProtoReflect.Descriptor instead.
func (*RawNebulaArgon2Parameters) Descriptor() ([]byte, []int) {
return file_cert_v1_proto_rawDescGZIP(), []int{4}
}
func (x *RawNebulaArgon2Parameters) GetVersion() int32 {
if x != nil {
return x.Version
}
return 0
}
func (x *RawNebulaArgon2Parameters) GetMemory() uint32 {
if x != nil {
return x.Memory
}
return 0
}
func (x *RawNebulaArgon2Parameters) GetParallelism() uint32 {
if x != nil {
return x.Parallelism
}
return 0
}
func (x *RawNebulaArgon2Parameters) GetIterations() uint32 {
if x != nil {
return x.Iterations
}
return 0
}
func (x *RawNebulaArgon2Parameters) GetSalt() []byte {
if x != nil {
return x.Salt
}
return nil
}
var File_cert_v1_proto protoreflect.FileDescriptor
var file_cert_v1_proto_rawDesc = []byte{
0x0a, 0x0d, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x76, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x04, 0x63, 0x65, 0x72, 0x74, 0x22, 0x71, 0x0a, 0x14, 0x52, 0x61, 0x77, 0x4e, 0x65, 0x62, 0x75,
0x6c, 0x61, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a,
0x07, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21,
0x2e, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x52, 0x61, 0x77, 0x4e, 0x65, 0x62, 0x75, 0x6c, 0x61, 0x43,
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c,
0x73, 0x52, 0x07, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69,
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x53,
0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x9c, 0x02, 0x0a, 0x1b, 0x52, 0x61, 0x77,
0x4e, 0x65, 0x62, 0x75, 0x6c, 0x61, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03,
0x49, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x03, 0x49, 0x70, 0x73, 0x12, 0x18,
0x0a, 0x07, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52,
0x07, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x72, 0x6f, 0x75,
0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73,
0x12, 0x1c, 0x0a, 0x09, 0x4e, 0x6f, 0x74, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x05, 0x20,
0x01, 0x28, 0x03, 0x52, 0x09, 0x4e, 0x6f, 0x74, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x1a,
0x0a, 0x08, 0x4e, 0x6f, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03,
0x52, 0x08, 0x4e, 0x6f, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x75,
0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x50,
0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x49, 0x73, 0x43, 0x41,
0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x49, 0x73, 0x43, 0x41, 0x12, 0x16, 0x0a, 0x06,
0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x49, 0x73,
0x73, 0x75, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x05, 0x63, 0x75, 0x72, 0x76, 0x65, 0x18, 0x64, 0x20,
0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x43, 0x75, 0x72, 0x76, 0x65,
0x52, 0x05, 0x63, 0x75, 0x72, 0x76, 0x65, 0x22, 0x8b, 0x01, 0x0a, 0x16, 0x52, 0x61, 0x77, 0x4e,
0x65, 0x62, 0x75, 0x6c, 0x61, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x44, 0x61,
0x74, 0x61, 0x12, 0x51, 0x0a, 0x12, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21,
0x2e, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x52, 0x61, 0x77, 0x4e, 0x65, 0x62, 0x75, 0x6c, 0x61, 0x45,
0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x52, 0x12, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74,
0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x43, 0x69, 0x70, 0x68, 0x65,
0x72, 0x74, 0x65, 0x78, 0x74, 0x22, 0x9c, 0x01, 0x0a, 0x1b, 0x52, 0x61, 0x77, 0x4e, 0x65, 0x62,
0x75, 0x6c, 0x61, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x30, 0x0a, 0x13, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x13, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c,
0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x4b, 0x0a, 0x10, 0x41, 0x72, 0x67, 0x6f, 0x6e,
0x32, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x52, 0x61, 0x77, 0x4e, 0x65, 0x62, 0x75,
0x6c, 0x61, 0x41, 0x72, 0x67, 0x6f, 0x6e, 0x32, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
0x72, 0x73, 0x52, 0x10, 0x41, 0x72, 0x67, 0x6f, 0x6e, 0x32, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65,
0x74, 0x65, 0x72, 0x73, 0x22, 0xa3, 0x01, 0x0a, 0x19, 0x52, 0x61, 0x77, 0x4e, 0x65, 0x62, 0x75,
0x6c, 0x61, 0x41, 0x72, 0x67, 0x6f, 0x6e, 0x32, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20,
0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06,
0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6d, 0x65,
0x6d, 0x6f, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c,
0x69, 0x73, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c,
0x6c, 0x65, 0x6c, 0x69, 0x73, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x69, 0x74, 0x65, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x61, 0x6c, 0x74, 0x18, 0x05,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x73, 0x61, 0x6c, 0x74, 0x2a, 0x21, 0x0a, 0x05, 0x43, 0x75,
0x72, 0x76, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x55, 0x52, 0x56, 0x45, 0x32, 0x35, 0x35, 0x31,
0x39, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x32, 0x35, 0x36, 0x10, 0x01, 0x42, 0x20, 0x5a,
0x1e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6c, 0x61, 0x63,
0x6b, 0x68, 0x71, 0x2f, 0x6e, 0x65, 0x62, 0x75, 0x6c, 0x61, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_cert_v1_proto_rawDescOnce sync.Once
file_cert_v1_proto_rawDescData = file_cert_v1_proto_rawDesc
)
func file_cert_v1_proto_rawDescGZIP() []byte {
file_cert_v1_proto_rawDescOnce.Do(func() {
file_cert_v1_proto_rawDescData = protoimpl.X.CompressGZIP(file_cert_v1_proto_rawDescData)
})
return file_cert_v1_proto_rawDescData
}
var file_cert_v1_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_cert_v1_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_cert_v1_proto_goTypes = []any{
(Curve)(0), // 0: cert.Curve
(*RawNebulaCertificate)(nil), // 1: cert.RawNebulaCertificate
(*RawNebulaCertificateDetails)(nil), // 2: cert.RawNebulaCertificateDetails
(*RawNebulaEncryptedData)(nil), // 3: cert.RawNebulaEncryptedData
(*RawNebulaEncryptionMetadata)(nil), // 4: cert.RawNebulaEncryptionMetadata
(*RawNebulaArgon2Parameters)(nil), // 5: cert.RawNebulaArgon2Parameters
}
var file_cert_v1_proto_depIdxs = []int32{
2, // 0: cert.RawNebulaCertificate.Details:type_name -> cert.RawNebulaCertificateDetails
0, // 1: cert.RawNebulaCertificateDetails.curve:type_name -> cert.Curve
4, // 2: cert.RawNebulaEncryptedData.EncryptionMetadata:type_name -> cert.RawNebulaEncryptionMetadata
5, // 3: cert.RawNebulaEncryptionMetadata.Argon2Parameters:type_name -> cert.RawNebulaArgon2Parameters
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_cert_v1_proto_init() }
func file_cert_v1_proto_init() {
if File_cert_v1_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_cert_v1_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*RawNebulaCertificate); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cert_v1_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*RawNebulaCertificateDetails); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cert_v1_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*RawNebulaEncryptedData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cert_v1_proto_msgTypes[3].Exporter = func(v any, i int) any {
switch v := v.(*RawNebulaEncryptionMetadata); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cert_v1_proto_msgTypes[4].Exporter = func(v any, i int) any {
switch v := v.(*RawNebulaArgon2Parameters); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_cert_v1_proto_rawDesc,
NumEnums: 1,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_cert_v1_proto_goTypes,
DependencyIndexes: file_cert_v1_proto_depIdxs,
EnumInfos: file_cert_v1_proto_enumTypes,
MessageInfos: file_cert_v1_proto_msgTypes,
}.Build()
File_cert_v1_proto = out.File
file_cert_v1_proto_rawDesc = nil
file_cert_v1_proto_goTypes = nil
file_cert_v1_proto_depIdxs = nil
}
================================================
FILE: cert/cert_v1.proto
================================================
syntax = "proto3";
package cert;
option go_package = "github.com/slackhq/nebula/cert";
//import "google/protobuf/timestamp.proto";
enum Curve {
CURVE25519 = 0;
P256 = 1;
}
message RawNebulaCertificate {
RawNebulaCertificateDetails Details = 1;
bytes Signature = 2;
}
message RawNebulaCertificateDetails {
string Name = 1;
// Ips and Subnets are in big endian 32 bit pairs, 1st the ip, 2nd the mask
repeated uint32 Ips = 2;
repeated uint32 Subnets = 3;
repeated stri
gitextract_aqr65ra4/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.yml
│ │ └── config.yml
│ ├── dependabot.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── gofmt.yml
│ ├── release.yml
│ ├── smoke/
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ ├── build-relay.sh
│ │ ├── build.sh
│ │ ├── genconfig.sh
│ │ ├── smoke-relay.sh
│ │ ├── smoke-vagrant.sh
│ │ ├── smoke.sh
│ │ ├── vagrant-freebsd-amd64/
│ │ │ └── Vagrantfile
│ │ ├── vagrant-linux-386/
│ │ │ └── Vagrantfile
│ │ ├── vagrant-linux-amd64-ipv6disable/
│ │ │ └── Vagrantfile
│ │ ├── vagrant-netbsd-amd64/
│ │ │ └── Vagrantfile
│ │ └── vagrant-openbsd-amd64/
│ │ └── Vagrantfile
│ ├── smoke-extra.yml
│ ├── smoke.yml
│ └── test.yml
├── .gitignore
├── .golangci.yaml
├── AUTHORS
├── CHANGELOG.md
├── CODEOWNERS
├── LICENSE
├── LOGGING.md
├── Makefile
├── README.md
├── SECURITY.md
├── allow_list.go
├── allow_list_test.go
├── bits.go
├── bits_test.go
├── boring.go
├── calculated_remote.go
├── calculated_remote_test.go
├── cert/
│ ├── Makefile
│ ├── README.md
│ ├── asn1.go
│ ├── ca_pool.go
│ ├── ca_pool_test.go
│ ├── cert.go
│ ├── cert_v1.go
│ ├── cert_v1.pb.go
│ ├── cert_v1.proto
│ ├── cert_v1_test.go
│ ├── cert_v2.asn1
│ ├── cert_v2.go
│ ├── cert_v2_test.go
│ ├── crypto.go
│ ├── crypto_test.go
│ ├── errors.go
│ ├── helper_test.go
│ ├── p256/
│ │ ├── p256.go
│ │ └── p256_test.go
│ ├── pem.go
│ ├── pem_test.go
│ ├── sign.go
│ └── sign_test.go
├── cert_test/
│ └── cert.go
├── cmd/
│ ├── nebula/
│ │ ├── main.go
│ │ ├── notify_linux.go
│ │ └── notify_notlinux.go
│ ├── nebula-cert/
│ │ ├── ca.go
│ │ ├── ca_test.go
│ │ ├── keygen.go
│ │ ├── keygen_test.go
│ │ ├── main.go
│ │ ├── main_test.go
│ │ ├── p11_cgo.go
│ │ ├── p11_stub.go
│ │ ├── passwords.go
│ │ ├── passwords_test.go
│ │ ├── print.go
│ │ ├── print_test.go
│ │ ├── sign.go
│ │ ├── sign_test.go
│ │ ├── test_darwin.go
│ │ ├── test_linux.go
│ │ ├── test_windows.go
│ │ ├── verify.go
│ │ └── verify_test.go
│ └── nebula-service/
│ ├── logs_generic.go
│ ├── logs_windows.go
│ ├── main.go
│ └── service.go
├── config/
│ ├── config.go
│ └── config_test.go
├── connection_manager.go
├── connection_manager_test.go
├── connection_state.go
├── control.go
├── control_test.go
├── control_tester.go
├── dist/
│ ├── windows/
│ │ └── wintun/
│ │ ├── LICENSE.txt
│ │ ├── README.md
│ │ └── include/
│ │ └── wintun.h
│ └── wireshark/
│ └── nebula.lua
├── dns_server.go
├── dns_server_test.go
├── docker/
│ ├── Dockerfile
│ └── README.md
├── e2e/
│ ├── doc.go
│ ├── handshakes_test.go
│ ├── helpers_test.go
│ ├── router/
│ │ ├── doc.go
│ │ ├── hostmap.go
│ │ └── router.go
│ └── tunnels_test.go
├── examples/
│ ├── config.yml
│ ├── go_service/
│ │ └── main.go
│ └── service_scripts/
│ ├── nebula.init.d.sh
│ ├── nebula.open-rc
│ ├── nebula.plist
│ └── nebula.service
├── firewall/
│ ├── cache.go
│ └── packet.go
├── firewall.go
├── firewall_test.go
├── go.mod
├── go.sum
├── handshake_ix.go
├── handshake_manager.go
├── handshake_manager_test.go
├── header/
│ ├── header.go
│ └── header_test.go
├── hostmap.go
├── hostmap_test.go
├── hostmap_tester.go
├── inside.go
├── inside_bsd.go
├── inside_generic.go
├── interface.go
├── iputil/
│ ├── packet.go
│ └── packet_test.go
├── lighthouse.go
├── lighthouse_test.go
├── logger.go
├── main.go
├── message_metrics.go
├── nebula.pb.go
├── nebula.proto
├── noise.go
├── noiseutil/
│ ├── boring.go
│ ├── boring_test.go
│ ├── nist.go
│ ├── notboring.go
│ ├── notboring_test.go
│ └── pkcs11.go
├── notboring.go
├── outside.go
├── outside_test.go
├── overlay/
│ ├── device.go
│ ├── route.go
│ ├── route_test.go
│ ├── tun.go
│ ├── tun_android.go
│ ├── tun_darwin.go
│ ├── tun_disabled.go
│ ├── tun_freebsd.go
│ ├── tun_ios.go
│ ├── tun_linux.go
│ ├── tun_linux_test.go
│ ├── tun_netbsd.go
│ ├── tun_notwin.go
│ ├── tun_openbsd.go
│ ├── tun_tester.go
│ ├── tun_windows.go
│ └── user.go
├── pkclient/
│ ├── pkclient.go
│ ├── pkclient_cgo.go
│ └── pkclient_stub.go
├── pki.go
├── punchy.go
├── punchy_test.go
├── relay_manager.go
├── remote_list.go
├── remote_list_test.go
├── routing/
│ ├── balance.go
│ ├── balance_test.go
│ ├── gateway.go
│ └── gateway_test.go
├── service/
│ ├── listener.go
│ ├── service.go
│ └── service_test.go
├── ssh.go
├── sshd/
│ ├── command.go
│ ├── server.go
│ ├── session.go
│ └── writer.go
├── stats.go
├── test/
│ ├── assert.go
│ ├── logger.go
│ └── tun.go
├── timeout.go
├── timeout_test.go
├── udp/
│ ├── conn.go
│ ├── errors.go
│ ├── udp_android.go
│ ├── udp_bsd.go
│ ├── udp_darwin.go
│ ├── udp_generic.go
│ ├── udp_linux.go
│ ├── udp_linux_32.go
│ ├── udp_linux_64.go
│ ├── udp_netbsd.go
│ ├── udp_rio_windows.go
│ ├── udp_tester.go
│ └── udp_windows.go
├── util/
│ ├── error.go
│ └── error_test.go
└── wintun/
├── device.go
└── tun.go
SYMBOL INDEX (1912 symbols across 162 files)
FILE: allow_list.go
type AllowList (line 12) | type AllowList struct
method Allow (line 239) | func (al *AllowList) Allow(addr netip.Addr) bool {
type RemoteAllowList (line 17) | type RemoteAllowList struct
method AllowUnknownVpnAddr (line 270) | func (al *RemoteAllowList) AllowUnknownVpnAddr(vpnAddr netip.Addr) bool {
method Allow (line 277) | func (al *RemoteAllowList) Allow(vpnAddr netip.Addr, udpAddr netip.Add...
method AllowAll (line 284) | func (al *RemoteAllowList) AllowAll(vpnAddrs []netip.Addr, udpAddr net...
method getInsideAllowList (line 298) | func (al *RemoteAllowList) getInsideAllowList(vpnAddr netip.Addr) *All...
type LocalAllowList (line 25) | type LocalAllowList struct
method Allow (line 248) | func (al *LocalAllowList) Allow(udpAddr netip.Addr) bool {
method AllowName (line 255) | func (al *LocalAllowList) AllowName(name string) bool {
type AllowListNameRule (line 32) | type AllowListNameRule struct
function NewLocalAllowListFromConfig (line 37) | func NewLocalAllowListFromConfig(c *config.C, k string) (*LocalAllowList...
function NewRemoteAllowListFromConfig (line 59) | func NewRemoteAllowListFromConfig(c *config.C, k, rangesKey string) (*Re...
function newAllowListFromConfig (line 73) | func newAllowListFromConfig(c *config.C, k string, handleKey func(key st...
function newAllowList (line 84) | func newAllowList(k string, raw any, handleKey func(key string, value an...
function getAllowListInterfaces (line 171) | func getAllowListInterfaces(k string, v any) ([]AllowListNameRule, error) {
function getRemoteAllowRanges (line 210) | func getRemoteAllowRanges(c *config.C, k string) (*bart.Table[*AllowList...
FILE: allow_list_test.go
function TestNewAllowListFromConfig (line 15) | func TestNewAllowListFromConfig(t *testing.T) {
function TestAllowList_Allow (line 101) | func TestAllowList_Allow(t *testing.T) {
function TestLocalAllowList_AllowName (line 124) | func TestLocalAllowList_AllowName(t *testing.T) {
FILE: bits.go
type Bits (line 8) | type Bits struct
method Check (line 33) | func (b *Bits) Check(l *logrus.Logger, i uint64) bool {
method Update (line 51) | func (b *Bits) Update(l *logrus.Logger, i uint64) bool {
function NewBits (line 17) | func NewBits(bits uint64) *Bits {
FILE: bits_test.go
function TestBits (line 10) | func TestBits(t *testing.T) {
function TestBitsLargeJumps (line 73) | func TestBitsLargeJumps(t *testing.T) {
function TestBitsDupeCounter (line 90) | func TestBitsDupeCounter(t *testing.T) {
function TestBitsOutOfWindowCounter (line 115) | func TestBitsOutOfWindowCounter(t *testing.T) {
function TestBitsLostCounter (line 144) | func TestBitsLostCounter(t *testing.T) {
function TestBitsLostCounterIssue1 (line 224) | func TestBitsLostCounterIssue1(t *testing.T) {
function BenchmarkBits (line 280) | func BenchmarkBits(b *testing.B) {
FILE: calculated_remote.go
type calculatedRemote (line 18) | type calculatedRemote struct
method String (line 41) | func (c *calculatedRemote) String() string {
method ApplyV4 (line 45) | func (c *calculatedRemote) ApplyV4(addr netip.Addr) *V4AddrPort {
method ApplyV6 (line 59) | func (c *calculatedRemote) ApplyV6(addr netip.Addr) *V6AddrPort {
function newCalculatedRemote (line 24) | func newCalculatedRemote(cidr, maskCidr netip.Prefix, port int) (*calcul...
function NewCalculatedRemotesFromConfig (line 79) | func NewCalculatedRemotesFromConfig(c *config.C, k string) (*bart.Table[...
function newCalculatedRemotesListFromConfig (line 108) | func newCalculatedRemotesListFromConfig(cidr netip.Prefix, raw any) ([]*...
function newCalculatedRemotesEntryFromConfig (line 126) | func newCalculatedRemotesEntryFromConfig(cidr netip.Prefix, raw any) (*c...
FILE: calculated_remote_test.go
function TestCalculatedRemoteApply (line 11) | func TestCalculatedRemoteApply(t *testing.T) {
function Test_newCalculatedRemote (line 65) | func Test_newCalculatedRemote(t *testing.T) {
FILE: cert/asn1.go
function readOptionalASN1Boolean (line 10) | func readOptionalASN1Boolean(b *cryptobyte.String, out *bool, tag asn1.T...
function readOptionalASN1Byte (line 33) | func readOptionalASN1Byte(b *cryptobyte.String, out *byte, tag asn1.Tag,...
FILE: cert/ca_pool.go
type CAPool (line 12) | type CAPool struct
method AddCAFromPEM (line 59) | func (ncp *CAPool) AddCAFromPEM(pemBytes []byte) ([]byte, error) {
method AddCA (line 74) | func (ncp *CAPool) AddCA(c Certificate) error {
method BlocklistFingerprint (line 108) | func (ncp *CAPool) BlocklistFingerprint(f string) {
method ResetCertBlocklist (line 113) | func (ncp *CAPool) ResetCertBlocklist() {
method IsBlocklisted (line 119) | func (ncp *CAPool) IsBlocklisted(fingerprint string) bool {
method VerifyCertificate (line 130) | func (ncp *CAPool) VerifyCertificate(now time.Time, c Certificate) (*C...
method VerifyCachedCertificate (line 173) | func (ncp *CAPool) VerifyCachedCertificate(now time.Time, c *CachedCer...
method verify (line 183) | func (ncp *CAPool) verify(c Certificate, now time.Time, certFp string,...
method GetCAForCert (line 223) | func (ncp *CAPool) GetCAForCert(c Certificate) (*CachedCertificate, er...
method GetFingerprints (line 238) | func (ncp *CAPool) GetFingerprints() []string {
function NewCAPool (line 18) | func NewCAPool() *CAPool {
function NewCAPoolFromPEM (line 31) | func NewCAPoolFromPEM(caPEMs []byte) (*CAPool, error) {
function CheckCAConstraints (line 251) | func CheckCAConstraints(signer Certificate, sub Certificate) error {
function checkCAConstraints (line 256) | func checkCAConstraints(signer Certificate, notBefore, notAfter time.Tim...
FILE: cert/ca_pool_test.go
function TestNewCAPoolFromBytes (line 13) | func TestNewCAPoolFromBytes(t *testing.T) {
function TestCertificateV1_Verify (line 115) | func TestCertificateV1_Verify(t *testing.T) {
function TestCertificateV1_VerifyP256 (line 160) | func TestCertificateV1_VerifyP256(t *testing.T) {
function TestCertificateV1_Verify_IPs (line 223) | func TestCertificateV1_Verify_IPs(t *testing.T) {
function TestCertificateV1_Verify_Subnets (line 290) | func TestCertificateV1_Verify_Subnets(t *testing.T) {
function TestCertificateV2_Verify (line 358) | func TestCertificateV2_Verify(t *testing.T) {
function TestCertificateV2_VerifyP256 (line 403) | func TestCertificateV2_VerifyP256(t *testing.T) {
function TestCertificateV2_Verify_IPs (line 466) | func TestCertificateV2_Verify_IPs(t *testing.T) {
function TestCertificateV2_Verify_Subnets (line 533) | func TestCertificateV2_Verify_Subnets(t *testing.T) {
FILE: cert/cert.go
type Version (line 11) | type Version
constant VersionPre1 (line 14) | VersionPre1 Version = 0
constant Version1 (line 15) | Version1 Version = 1
constant Version2 (line 16) | Version2 Version = 2
type Certificate (line 19) | type Certificate interface
type CachedCertificate (line 110) | type CachedCertificate struct
method String (line 120) | func (cc *CachedCertificate) String() string {
function Recombine (line 128) | func Recombine(v Version, rawCertBytes, publicKey []byte, curve Curve) (...
function CalculateAlternateFingerprint (line 163) | func CalculateAlternateFingerprint(c Certificate) (string, error) {
FILE: cert/cert_v1.go
constant publicKeyLen (line 23) | publicKeyLen = 32
type certificateV1 (line 25) | type certificateV1 struct
method Version (line 46) | func (c *certificateV1) Version() Version {
method Curve (line 50) | func (c *certificateV1) Curve() Curve {
method Groups (line 54) | func (c *certificateV1) Groups() []string {
method IsCA (line 58) | func (c *certificateV1) IsCA() bool {
method Issuer (line 62) | func (c *certificateV1) Issuer() string {
method Name (line 66) | func (c *certificateV1) Name() string {
method Networks (line 70) | func (c *certificateV1) Networks() []netip.Prefix {
method NotAfter (line 74) | func (c *certificateV1) NotAfter() time.Time {
method NotBefore (line 78) | func (c *certificateV1) NotBefore() time.Time {
method PublicKey (line 82) | func (c *certificateV1) PublicKey() []byte {
method MarshalPublicKeyPEM (line 86) | func (c *certificateV1) MarshalPublicKeyPEM() []byte {
method Signature (line 90) | func (c *certificateV1) Signature() []byte {
method UnsafeNetworks (line 94) | func (c *certificateV1) UnsafeNetworks() []netip.Prefix {
method Fingerprint (line 98) | func (c *certificateV1) Fingerprint() (string, error) {
method CheckSignature (line 108) | func (c *certificateV1) CheckSignature(key []byte) bool {
method Expired (line 128) | func (c *certificateV1) Expired(t time.Time) bool {
method VerifyPrivateKey (line 132) | func (c *certificateV1) VerifyPrivateKey(curve Curve, key []byte) error {
method getRawDetails (line 187) | func (c *certificateV1) getRawDetails() *RawNebulaCertificateDetails {
method String (line 216) | func (c *certificateV1) String() string {
method MarshalForHandshakes (line 224) | func (c *certificateV1) MarshalForHandshakes() ([]byte, error) {
method Marshal (line 235) | func (c *certificateV1) Marshal() ([]byte, error) {
method MarshalPEM (line 244) | func (c *certificateV1) MarshalPEM() ([]byte, error) {
method MarshalJSON (line 252) | func (c *certificateV1) MarshalJSON() ([]byte, error) {
method marshalJSON (line 256) | func (c *certificateV1) marshalJSON() m {
method Copy (line 277) | func (c *certificateV1) Copy() Certificate {
method fromTBSCertificate (line 312) | func (c *certificateV1) fromTBSCertificate(t *TBSCertificate) error {
method validate (line 329) | func (c *certificateV1) validate() error {
method marshalForSigning (line 381) | func (c *certificateV1) marshalForSigning() ([]byte, error) {
method setSignature (line 389) | func (c *certificateV1) setSignature(b []byte) error {
type detailsV1 (line 30) | type detailsV1 struct
function unmarshalCertificateV1 (line 399) | func unmarshalCertificateV1(b []byte, publicKey []byte) (*certificateV1,...
function ip2int (line 480) | func ip2int(ip []byte) uint32 {
function int2ip (line 487) | func int2ip(nn uint32) net.IP {
function addr2int (line 493) | func addr2int(addr netip.Addr) uint32 {
function int2addr (line 498) | func int2addr(nn uint32) netip.Addr {
FILE: cert/cert_v1.pb.go
constant _ (line 18) | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
constant _ (line 20) | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
type Curve (line 23) | type Curve
method Enum (line 42) | func (x Curve) Enum() *Curve {
method String (line 48) | func (x Curve) String() string {
method Descriptor (line 52) | func (Curve) Descriptor() protoreflect.EnumDescriptor {
method Type (line 56) | func (Curve) Type() protoreflect.EnumType {
method Number (line 60) | func (x Curve) Number() protoreflect.EnumNumber {
method EnumDescriptor (line 65) | func (Curve) EnumDescriptor() ([]byte, []int) {
constant Curve_CURVE25519 (line 26) | Curve_CURVE25519 Curve = 0
constant Curve_P256 (line 27) | Curve_P256 Curve = 1
type RawNebulaCertificate (line 69) | type RawNebulaCertificate struct
method Reset (line 78) | func (x *RawNebulaCertificate) Reset() {
method String (line 87) | func (x *RawNebulaCertificate) String() string {
method ProtoMessage (line 91) | func (*RawNebulaCertificate) ProtoMessage() {}
method ProtoReflect (line 93) | func (x *RawNebulaCertificate) ProtoReflect() protoreflect.Message {
method Descriptor (line 106) | func (*RawNebulaCertificate) Descriptor() ([]byte, []int) {
method GetDetails (line 110) | func (x *RawNebulaCertificate) GetDetails() *RawNebulaCertificateDetai...
method GetSignature (line 117) | func (x *RawNebulaCertificate) GetSignature() []byte {
type RawNebulaCertificateDetails (line 124) | type RawNebulaCertificateDetails struct
method Reset (line 143) | func (x *RawNebulaCertificateDetails) Reset() {
method String (line 152) | func (x *RawNebulaCertificateDetails) String() string {
method ProtoMessage (line 156) | func (*RawNebulaCertificateDetails) ProtoMessage() {}
method ProtoReflect (line 158) | func (x *RawNebulaCertificateDetails) ProtoReflect() protoreflect.Mess...
method Descriptor (line 171) | func (*RawNebulaCertificateDetails) Descriptor() ([]byte, []int) {
method GetName (line 175) | func (x *RawNebulaCertificateDetails) GetName() string {
method GetIps (line 182) | func (x *RawNebulaCertificateDetails) GetIps() []uint32 {
method GetSubnets (line 189) | func (x *RawNebulaCertificateDetails) GetSubnets() []uint32 {
method GetGroups (line 196) | func (x *RawNebulaCertificateDetails) GetGroups() []string {
method GetNotBefore (line 203) | func (x *RawNebulaCertificateDetails) GetNotBefore() int64 {
method GetNotAfter (line 210) | func (x *RawNebulaCertificateDetails) GetNotAfter() int64 {
method GetPublicKey (line 217) | func (x *RawNebulaCertificateDetails) GetPublicKey() []byte {
method GetIsCA (line 224) | func (x *RawNebulaCertificateDetails) GetIsCA() bool {
method GetIssuer (line 231) | func (x *RawNebulaCertificateDetails) GetIssuer() []byte {
method GetCurve (line 238) | func (x *RawNebulaCertificateDetails) GetCurve() Curve {
type RawNebulaEncryptedData (line 245) | type RawNebulaEncryptedData struct
method Reset (line 254) | func (x *RawNebulaEncryptedData) Reset() {
method String (line 263) | func (x *RawNebulaEncryptedData) String() string {
method ProtoMessage (line 267) | func (*RawNebulaEncryptedData) ProtoMessage() {}
method ProtoReflect (line 269) | func (x *RawNebulaEncryptedData) ProtoReflect() protoreflect.Message {
method Descriptor (line 282) | func (*RawNebulaEncryptedData) Descriptor() ([]byte, []int) {
method GetEncryptionMetadata (line 286) | func (x *RawNebulaEncryptedData) GetEncryptionMetadata() *RawNebulaEnc...
method GetCiphertext (line 293) | func (x *RawNebulaEncryptedData) GetCiphertext() []byte {
type RawNebulaEncryptionMetadata (line 300) | type RawNebulaEncryptionMetadata struct
method Reset (line 309) | func (x *RawNebulaEncryptionMetadata) Reset() {
method String (line 318) | func (x *RawNebulaEncryptionMetadata) String() string {
method ProtoMessage (line 322) | func (*RawNebulaEncryptionMetadata) ProtoMessage() {}
method ProtoReflect (line 324) | func (x *RawNebulaEncryptionMetadata) ProtoReflect() protoreflect.Mess...
method Descriptor (line 337) | func (*RawNebulaEncryptionMetadata) Descriptor() ([]byte, []int) {
method GetEncryptionAlgorithm (line 341) | func (x *RawNebulaEncryptionMetadata) GetEncryptionAlgorithm() string {
method GetArgon2Parameters (line 348) | func (x *RawNebulaEncryptionMetadata) GetArgon2Parameters() *RawNebula...
type RawNebulaArgon2Parameters (line 355) | type RawNebulaArgon2Parameters struct
method Reset (line 367) | func (x *RawNebulaArgon2Parameters) Reset() {
method String (line 376) | func (x *RawNebulaArgon2Parameters) String() string {
method ProtoMessage (line 380) | func (*RawNebulaArgon2Parameters) ProtoMessage() {}
method ProtoReflect (line 382) | func (x *RawNebulaArgon2Parameters) ProtoReflect() protoreflect.Message {
method Descriptor (line 395) | func (*RawNebulaArgon2Parameters) Descriptor() ([]byte, []int) {
method GetVersion (line 399) | func (x *RawNebulaArgon2Parameters) GetVersion() int32 {
method GetMemory (line 406) | func (x *RawNebulaArgon2Parameters) GetMemory() uint32 {
method GetParallelism (line 413) | func (x *RawNebulaArgon2Parameters) GetParallelism() uint32 {
method GetIterations (line 420) | func (x *RawNebulaArgon2Parameters) GetIterations() uint32 {
method GetSalt (line 427) | func (x *RawNebulaArgon2Parameters) GetSalt() []byte {
function file_cert_v1_proto_rawDescGZIP (line 505) | func file_cert_v1_proto_rawDescGZIP() []byte {
function init (line 534) | func init() { file_cert_v1_proto_init() }
function file_cert_v1_proto_init (line 535) | func file_cert_v1_proto_init() {
FILE: cert/cert_v1_test.go
function TestCertificateV1_Marshal (line 16) | func TestCertificateV1_Marshal(t *testing.T) {
function TestCertificateV1_Unmarshal (line 65) | func TestCertificateV1_Unmarshal(t *testing.T) {
function TestCertificateV1_PublicKeyPem (line 121) | func TestCertificateV1_PublicKeyPem(t *testing.T) {
function TestCertificateV1_Expired (line 179) | func TestCertificateV1_Expired(t *testing.T) {
function TestCertificateV1_MarshalJSON (line 192) | func TestCertificateV1_MarshalJSON(t *testing.T) {
function TestCertificateV1_VerifyPrivateKey (line 226) | func TestCertificateV1_VerifyPrivateKey(t *testing.T) {
function TestCertificateV1_VerifyPrivateKeyP256 (line 249) | func TestCertificateV1_VerifyPrivateKeyP256(t *testing.T) {
function TestMarshalingCertificateV1Consistency (line 274) | func TestMarshalingCertificateV1Consistency(t *testing.T) {
function TestCertificateV1_Copy (line 309) | func TestCertificateV1_Copy(t *testing.T) {
function TestUnmarshalCertificateV1 (line 316) | func TestUnmarshalCertificateV1(t *testing.T) {
function appendByteSlices (line 323) | func appendByteSlices(b ...[]byte) []byte {
function mustParsePrefixUnmapped (line 331) | func mustParsePrefixUnmapped(s string) netip.Prefix {
FILE: cert/cert_v2.go
constant classConstructed (line 24) | classConstructed = 0x20
constant classContextSpecific (line 25) | classContextSpecific = 0x80
constant TagCertDetails (line 27) | TagCertDetails = 0 | classConstructed | classContextSpecific
constant TagCertCurve (line 28) | TagCertCurve = 1 | classContextSpecific
constant TagCertPublicKey (line 29) | TagCertPublicKey = 2 | classContextSpecific
constant TagCertSignature (line 30) | TagCertSignature = 3 | classContextSpecific
constant TagDetailsName (line 32) | TagDetailsName = 0 | classContextSpecific
constant TagDetailsNetworks (line 33) | TagDetailsNetworks = 1 | classConstructed | classContextSpecific
constant TagDetailsUnsafeNetworks (line 34) | TagDetailsUnsafeNetworks = 2 | classConstructed | classContextSpecific
constant TagDetailsGroups (line 35) | TagDetailsGroups = 3 | classConstructed | classContextSpecific
constant TagDetailsIsCA (line 36) | TagDetailsIsCA = 4 | classContextSpecific
constant TagDetailsNotBefore (line 37) | TagDetailsNotBefore = 5 | classContextSpecific
constant TagDetailsNotAfter (line 38) | TagDetailsNotAfter = 6 | classContextSpecific
constant TagDetailsIssuer (line 39) | TagDetailsIssuer = 7 | classContextSpecific
constant MaxCertificateSize (line 44) | MaxCertificateSize = 65536
constant MaxNameLength (line 47) | MaxNameLength = 253
constant MaxNetworkLength (line 51) | MaxNetworkLength = 17
type certificateV2 (line 54) | type certificateV2 struct
method Version (line 77) | func (c *certificateV2) Version() Version {
method Curve (line 81) | func (c *certificateV2) Curve() Curve {
method Groups (line 85) | func (c *certificateV2) Groups() []string {
method IsCA (line 89) | func (c *certificateV2) IsCA() bool {
method Issuer (line 93) | func (c *certificateV2) Issuer() string {
method Name (line 97) | func (c *certificateV2) Name() string {
method Networks (line 101) | func (c *certificateV2) Networks() []netip.Prefix {
method NotAfter (line 105) | func (c *certificateV2) NotAfter() time.Time {
method NotBefore (line 109) | func (c *certificateV2) NotBefore() time.Time {
method PublicKey (line 113) | func (c *certificateV2) PublicKey() []byte {
method MarshalPublicKeyPEM (line 117) | func (c *certificateV2) MarshalPublicKeyPEM() []byte {
method Signature (line 121) | func (c *certificateV2) Signature() []byte {
method UnsafeNetworks (line 125) | func (c *certificateV2) UnsafeNetworks() []netip.Prefix {
method Fingerprint (line 129) | func (c *certificateV2) Fingerprint() (string, error) {
method CheckSignature (line 143) | func (c *certificateV2) CheckSignature(key []byte) bool {
method Expired (line 167) | func (c *certificateV2) Expired(t time.Time) bool {
method VerifyPrivateKey (line 171) | func (c *certificateV2) VerifyPrivateKey(curve Curve, key []byte) error {
method String (line 225) | func (c *certificateV2) String() string {
method MarshalForHandshakes (line 238) | func (c *certificateV2) MarshalForHandshakes() ([]byte, error) {
method Marshal (line 260) | func (c *certificateV2) Marshal() ([]byte, error) {
method MarshalPEM (line 294) | func (c *certificateV2) MarshalPEM() ([]byte, error) {
method MarshalJSON (line 302) | func (c *certificateV2) MarshalJSON() ([]byte, error) {
method marshalJSON (line 310) | func (c *certificateV2) marshalJSON() (m, error) {
method Copy (line 335) | func (c *certificateV2) Copy() Certificate {
method fromTBSCertificate (line 372) | func (c *certificateV2) fromTBSCertificate(t *TBSCertificate) error {
method validate (line 388) | func (c *certificateV2) validate() error {
method marshalForSigning (line 459) | func (c *certificateV2) marshalForSigning() ([]byte, error) {
method setSignature (line 473) | func (c *certificateV2) setSignature(b []byte) error {
type detailsV2 (line 66) | type detailsV2 struct
method Marshal (line 481) | func (d *detailsV2) Marshal() ([]byte, error) {
function unmarshalCertificateV2 (line 567) | func unmarshalCertificateV2(b []byte, publicKey []byte, curve Curve) (*c...
function unmarshalDetails (line 638) | func unmarshalDetails(b cryptobyte.String) (detailsV2, error) {
FILE: cert/cert_v2_test.go
function TestCertificateV2_Marshal (line 17) | func TestCertificateV2_Marshal(t *testing.T) {
function TestCertificateV2_Unmarshal (line 79) | func TestCertificateV2_Unmarshal(t *testing.T) {
function TestCertificateV2_PublicKeyPem (line 131) | func TestCertificateV2_PublicKeyPem(t *testing.T) {
function TestCertificateV2_Expired (line 190) | func TestCertificateV2_Expired(t *testing.T) {
function TestCertificateV2_MarshalJSON (line 203) | func TestCertificateV2_MarshalJSON(t *testing.T) {
function TestCertificateV2_VerifyPrivateKey (line 244) | func TestCertificateV2_VerifyPrivateKey(t *testing.T) {
function TestCertificateV2_VerifyPrivateKeyP256 (line 305) | func TestCertificateV2_VerifyPrivateKeyP256(t *testing.T) {
function TestCertificateV2_Copy (line 328) | func TestCertificateV2_Copy(t *testing.T) {
function TestUnmarshalCertificateV2 (line 335) | func TestUnmarshalCertificateV2(t *testing.T) {
function TestCertificateV2_marshalForSigningStability (line 341) | func TestCertificateV2_marshalForSigningStability(t *testing.T) {
FILE: cert/crypto.go
type NebulaEncryptedData (line 17) | type NebulaEncryptedData struct
type NebulaEncryptionMetadata (line 22) | type NebulaEncryptionMetadata struct
type Argon2Parameters (line 28) | type Argon2Parameters struct
function NewArgon2Parameters (line 37) | func NewArgon2Parameters(memory uint32, parallelism uint8, iterations ui...
function aes256Encrypt (line 47) | func aes256Encrypt(passphrase []byte, kdfParams *Argon2Parameters, data ...
function aes256Decrypt (line 82) | func aes256Decrypt(passphrase []byte, kdfParams *Argon2Parameters, data ...
function aes256DeriveKey (line 111) | func aes256DeriveKey(passphrase []byte, params *Argon2Parameters) ([]byt...
function deriveKey (line 129) | func deriveKey(passphrase []byte, keySize uint32, params *Argon2Paramete...
function joinNonceCiphertext (line 146) | func joinNonceCiphertext(nonce []byte, ciphertext []byte) []byte {
function splitNonceCiphertext (line 151) | func splitNonceCiphertext(blob []byte, nonceSize int) ([]byte, []byte, e...
function EncryptAndMarshalSigningPrivateKey (line 160) | func EncryptAndMarshalSigningPrivateKey(curve Curve, b []byte, passphras...
function UnmarshalNebulaEncryptedData (line 195) | func UnmarshalNebulaEncryptedData(b []byte) (*NebulaEncryptedData, error) {
function unmarshalArgon2Parameters (line 229) | func unmarshalArgon2Parameters(params *RawNebulaArgon2Parameters) (*Argo...
function DecryptAndUnmarshalSigningPrivateKey (line 255) | func DecryptAndUnmarshalSigningPrivateKey(passphrase, b []byte) (Curve, ...
FILE: cert/crypto_test.go
function TestNewArgon2Parameters (line 11) | func TestNewArgon2Parameters(t *testing.T) {
function TestDecryptAndUnmarshalSigningPrivateKey (line 28) | func TestDecryptAndUnmarshalSigningPrivateKey(t *testing.T) {
function TestEncryptAndMarshalSigningPrivateKey (line 96) | func TestEncryptAndMarshalSigningPrivateKey(t *testing.T) {
FILE: cert/errors.go
type ErrInvalidCertificateProperties (line 41) | type ErrInvalidCertificateProperties struct
method Error (line 49) | func (e *ErrInvalidCertificateProperties) Error() string {
function NewErrInvalidCertificateProperties (line 45) | func NewErrInvalidCertificateProperties(format string, a ...any) error {
FILE: cert/helper_test.go
function NewTestCaCert (line 17) | func NewTestCaCert(version Version, curve Curve, before, after time.Time...
function NewTestCert (line 71) | func NewTestCert(v Version, curve Curve, ca Certificate, key []byte, nam...
function X25519Keypair (line 120) | func X25519Keypair() ([]byte, []byte) {
function P256Keypair (line 134) | func P256Keypair() ([]byte, []byte) {
FILE: cert/p256/p256.go
function init (line 17) | func init() {
function IsNormalized (line 25) | func IsNormalized(sig []byte) (bool, error) {
function checkLowS (line 33) | func checkLowS(_, s []byte) bool {
function swap (line 39) | func swap(r, s []byte) ([]byte, []byte, error) {
function Normalize (line 50) | func Normalize(sig []byte) ([]byte, error) {
function Swap (line 69) | func Swap(sig []byte) ([]byte, error) {
function parseSignature (line 84) | func parseSignature(sig []byte) (r, s []byte, err error) {
function encodeSignature (line 97) | func encodeSignature(r, s []byte) ([]byte, error) {
function addASN1IntBytes (line 108) | func addASN1IntBytes(b *cryptobyte.Builder, bytes []byte) {
FILE: cert/p256/p256_test.go
function TestFlipping (line 12) | func TestFlipping(t *testing.T) {
FILE: cert/pem.go
constant CertificateBanner (line 11) | CertificateBanner = "NEBULA CERTIFICATE"
constant CertificateV2Banner (line 12) | CertificateV2Banner = "NEBULA CERTIFICATE V2"
constant X25519PrivateKeyBanner (line 16) | X25519PrivateKeyBanner = "NEBULA X25519 PRIVATE KEY"
constant X25519PublicKeyBanner (line 17) | X25519PublicKeyBanner = "NEBULA X25519 PUBLIC KEY"
constant P256PrivateKeyBanner (line 18) | P256PrivateKeyBanner = "NEBULA P256 PRIVATE KEY"
constant P256PublicKeyBanner (line 19) | P256PublicKeyBanner = "NEBULA P256 PUBLIC KEY"
constant EncryptedECDSAP256PrivateKeyBanner (line 24) | EncryptedECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 ENCRYPTED PRIVAT...
constant ECDSAP256PrivateKeyBanner (line 25) | ECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 PRIVATE KEY"
constant ECDSAP256PublicKeyBanner (line 26) | ECDSAP256PublicKeyBanner = "NEBULA ECDSA P256 PUBLIC KEY"
constant EncryptedEd25519PrivateKeyBanner (line 27) | EncryptedEd25519PrivateKeyBanner = "NEBULA ED25519 ENCRYPTED PRIVATE KEY"
constant Ed25519PrivateKeyBanner (line 28) | Ed25519PrivateKeyBanner = "NEBULA ED25519 PRIVATE KEY"
constant Ed25519PublicKeyBanner (line 29) | Ed25519PublicKeyBanner = "NEBULA ED25519 PUBLIC KEY"
function UnmarshalCertificateFromPEM (line 34) | func UnmarshalCertificateFromPEM(b []byte) (Certificate, []byte, error) {
function marshalCertPublicKeyToPEM (line 61) | func marshalCertPublicKeyToPEM(c Certificate) []byte {
function MarshalPublicKeyToPEM (line 71) | func MarshalPublicKeyToPEM(curve Curve, b []byte) []byte {
function MarshalSigningPublicKeyToPEM (line 84) | func MarshalSigningPublicKeyToPEM(curve Curve, b []byte) []byte {
function UnmarshalPublicKeyFromPEM (line 95) | func UnmarshalPublicKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
function MarshalPrivateKeyToPEM (line 119) | func MarshalPrivateKeyToPEM(curve Curve, b []byte) []byte {
function MarshalSigningPrivateKeyToPEM (line 130) | func MarshalSigningPrivateKeyToPEM(curve Curve, b []byte) []byte {
function UnmarshalPrivateKeyFromPEM (line 143) | func UnmarshalPrivateKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
function UnmarshalSigningPrivateKeyFromPEM (line 166) | func UnmarshalSigningPrivateKeyFromPEM(b []byte) ([]byte, []byte, Curve,...
FILE: cert/pem_test.go
function TestUnmarshalCertificateFromPEM (line 10) | func TestUnmarshalCertificateFromPEM(t *testing.T) {
function TestUnmarshalSigningPrivateKeyFromPEM (line 55) | func TestUnmarshalSigningPrivateKeyFromPEM(t *testing.T) {
function TestUnmarshalPrivateKeyFromPEM (line 117) | func TestUnmarshalPrivateKeyFromPEM(t *testing.T) {
function TestUnmarshalPublicKeyFromPEM (line 179) | func TestUnmarshalPublicKeyFromPEM(t *testing.T) {
function TestUnmarshalX25519PublicKey (line 233) | func TestUnmarshalX25519PublicKey(t *testing.T) {
FILE: cert/sign.go
type TBSCertificate (line 18) | type TBSCertificate struct
method Sign (line 49) | func (t *TBSCertificate) Sign(signer Certificate, curve Curve, key []b...
method SignWith (line 77) | func (t *TBSCertificate) SignWith(signer Certificate, curve Curve, sp ...
type beingSignedCertificate (line 32) | type beingSignedCertificate interface
type SignerLambda (line 44) | type SignerLambda
function comparePrefix (line 151) | func comparePrefix(a, b netip.Prefix) int {
function findDuplicatePrefix (line 160) | func findDuplicatePrefix(sortedPrefixes []netip.Prefix) error {
FILE: cert/sign_test.go
function TestCertificateV1_Sign (line 17) | func TestCertificateV1_Sign(t *testing.T) {
function TestCertificateV1_SignP256 (line 53) | func TestCertificateV1_SignP256(t *testing.T) {
function TestCertificate_SignP256_AlwaysNormalized (line 94) | func TestCertificate_SignP256_AlwaysNormalized(t *testing.T) {
FILE: cert_test/cert.go
function NewTestCaCert (line 18) | func NewTestCaCert(version cert.Version, curve cert.Curve, before, after...
function NewTestCert (line 72) | func NewTestCert(v cert.Version, curve cert.Curve, ca cert.Certificate, ...
function NewTestCertDifferentVersion (line 117) | func NewTestCertDifferentVersion(c cert.Certificate, v cert.Version, ca ...
function X25519Keypair (line 144) | func X25519Keypair() ([]byte, []byte) {
function P256Keypair (line 158) | func P256Keypair() ([]byte, []byte) {
FILE: cmd/nebula-cert/ca.go
type caFlags (line 22) | type caFlags struct
function newCaFlags (line 46) | func newCaFlags() *caFlags {
function parseArgonParameters (line 70) | func parseArgonParameters(memory uint, parallelism uint, iterations uint...
function ca (line 84) | func ca(args []string, out io.Writer, errOut io.Writer, pr PasswordReade...
function caSummary (line 328) | func caSummary() string {
function caHelp (line 332) | func caHelp(out io.Writer) {
FILE: cmd/nebula-cert/ca_test.go
function Test_caSummary (line 20) | func Test_caSummary(t *testing.T) {
function Test_caHelp (line 24) | func Test_caHelp(t *testing.T) {
function Test_ca (line 67) | func Test_ca(t *testing.T) {
FILE: cmd/nebula-cert/keygen.go
type keygenFlags (line 14) | type keygenFlags struct
function newKeygenFlags (line 22) | func newKeygenFlags() *keygenFlags {
function keygen (line 32) | func keygen(args []string, out io.Writer, errOut io.Writer) error {
function keygenSummary (line 98) | func keygenSummary() string {
function keygenHelp (line 102) | func keygenHelp(out io.Writer) {
FILE: cmd/nebula-cert/keygen_test.go
function Test_keygenSummary (line 13) | func Test_keygenSummary(t *testing.T) {
function Test_keygenHelp (line 17) | func Test_keygenHelp(t *testing.T) {
function Test_keygen (line 34) | func Test_keygen(t *testing.T) {
FILE: cmd/nebula-cert/main.go
function init (line 19) | func init() {
type helpError (line 30) | type helpError struct
method Error (line 34) | func (he *helpError) Error() string {
function newHelpErrorf (line 38) | func newHelpErrorf(s string, v ...any) error {
function main (line 42) | func main() {
function handleError (line 101) | func handleError(mode string, e error, out io.Writer) int {
function help (line 131) | func help(err string, out io.Writer) {
function mustFlagString (line 152) | func mustFlagString(name string, val *string) error {
FILE: cmd/nebula-cert/main_test.go
function Test_help (line 15) | func Test_help(t *testing.T) {
function Test_handleError (line 49) | func Test_handleError(t *testing.T) {
function assertHelpError (line 75) | func assertHelpError(t *testing.T, err error, msg string) {
function optionalPkcs11String (line 86) | func optionalPkcs11String(msg string) string {
FILE: cmd/nebula-cert/p11_cgo.go
function p11Supported (line 9) | func p11Supported() bool {
function p11Flag (line 13) | func p11Flag(set *flag.FlagSet) *string {
FILE: cmd/nebula-cert/p11_stub.go
function p11Supported (line 9) | func p11Supported() bool {
function p11Flag (line 13) | func p11Flag(set *flag.FlagSet) *string {
FILE: cmd/nebula-cert/passwords.go
type PasswordReader (line 13) | type PasswordReader interface
type StdinPasswordReader (line 17) | type StdinPasswordReader struct
method ReadPassword (line 19) | func (pr StdinPasswordReader) ReadPassword() ([]byte, error) {
FILE: cmd/nebula-cert/passwords_test.go
type StubPasswordReader (line 3) | type StubPasswordReader struct
method ReadPassword (line 8) | func (pr *StubPasswordReader) ReadPassword() ([]byte, error) {
FILE: cmd/nebula-cert/print.go
type printFlags (line 15) | type printFlags struct
function newPrintFlags (line 22) | func newPrintFlags() *printFlags {
function printCert (line 32) | func printCert(args []string, out io.Writer, errOut io.Writer) error {
function printSummary (line 103) | func printSummary() string {
function printHelp (line 107) | func printHelp(out io.Writer) {
FILE: cmd/nebula-cert/print_test.go
function Test_printSummary (line 18) | func Test_printSummary(t *testing.T) {
function Test_printHelp (line 22) | func Test_printHelp(t *testing.T) {
function Test_printCert (line 38) | func Test_printCert(t *testing.T) {
function NewTestCaCert (line 184) | func NewTestCaCert(name string, pubKey, privKey []byte, before, after ti...
function NewTestCert (line 213) | func NewTestCert(ca cert.Certificate, signerKey []byte, name string, bef...
FILE: cmd/nebula-cert/sign.go
type signFlags (line 21) | type signFlags struct
function newSignFlags (line 43) | func newSignFlags() *signFlags {
function signCert (line 65) | func signCert(args []string, out io.Writer, errOut io.Writer, pr Passwor...
function newKeypair (line 402) | func newKeypair(curve cert.Curve) ([]byte, []byte) {
function x25519Keypair (line 413) | func x25519Keypair() ([]byte, []byte) {
function p256Keypair (line 427) | func p256Keypair() ([]byte, []byte) {
function signSummary (line 436) | func signSummary() string {
function signHelp (line 440) | func signHelp(out io.Writer) {
FILE: cmd/nebula-cert/sign_test.go
function Test_signSummary (line 20) | func Test_signSummary(t *testing.T) {
function Test_signHelp (line 24) | func Test_signHelp(t *testing.T) {
function Test_signCert (line 63) | func Test_signCert(t *testing.T) {
FILE: cmd/nebula-cert/test_darwin.go
constant NoSuchFileError (line 3) | NoSuchFileError = "no such file or directory"
constant NoSuchDirError (line 4) | NoSuchDirError = "no such file or directory"
FILE: cmd/nebula-cert/test_linux.go
constant NoSuchFileError (line 3) | NoSuchFileError = "no such file or directory"
constant NoSuchDirError (line 4) | NoSuchDirError = "no such file or directory"
FILE: cmd/nebula-cert/test_windows.go
constant NoSuchFileError (line 3) | NoSuchFileError = "The system cannot find the file specified."
constant NoSuchDirError (line 4) | NoSuchDirError = "The system cannot find the path specified."
FILE: cmd/nebula-cert/verify.go
type verifyFlags (line 15) | type verifyFlags struct
function newVerifyFlags (line 21) | func newVerifyFlags() *verifyFlags {
function verify (line 29) | func verify(args []string, out io.Writer, errOut io.Writer) error {
function verifySummary (line 88) | func verifySummary() string {
function verifyHelp (line 92) | func verifyHelp(out io.Writer) {
FILE: cmd/nebula-cert/verify_test.go
function Test_verifySummary (line 16) | func Test_verifySummary(t *testing.T) {
function Test_verifyHelp (line 20) | func Test_verifyHelp(t *testing.T) {
function Test_verify (line 34) | func Test_verify(t *testing.T) {
FILE: cmd/nebula-service/logs_generic.go
function HookLogger (line 8) | func HookLogger(l *logrus.Logger) {
FILE: cmd/nebula-service/logs_windows.go
function HookLogger (line 14) | func HookLogger(l *logrus.Logger) {
type logHook (line 19) | type logHook struct
method Fire (line 27) | func (h *logHook) Fire(entry *logrus.Entry) error {
method Levels (line 52) | func (h *logHook) Levels() []logrus.Level {
function newLogHook (line 23) | func newLogHook(sl service.Logger) *logHook {
FILE: cmd/nebula-service/main.go
function init (line 23) | func init() {
function main (line 34) | func main() {
FILE: cmd/nebula-service/service.go
type program (line 17) | type program struct
method Start (line 24) | func (p *program) Start(s service.Service) error {
method Stop (line 46) | func (p *program) Stop(s service.Service) error {
function fileExists (line 52) | func fileExists(filename string) bool {
function doService (line 60) | func doService(configPath *string, configTest *bool, build string, servi...
FILE: cmd/nebula/main.go
function init (line 23) | func init() {
function main (line 34) | func main() {
FILE: cmd/nebula/notify_linux.go
constant SdNotifyReady (line 14) | SdNotifyReady = "READY=1"
function notifyReady (line 16) | func notifyReady(l *logrus.Logger) {
FILE: cmd/nebula/notify_notlinux.go
function notifyReady (line 8) | func notifyReady(_ *logrus.Logger) {
FILE: config/config.go
type C (line 23) | type C struct
method Load (line 41) | func (c *C) Load(path string) error {
method LoadString (line 64) | func (c *C) LoadString(raw string) error {
method RegisterReloadCallback (line 75) | func (c *C) RegisterReloadCallback(f func(*C)) {
method InitialLoad (line 80) | func (c *C) InitialLoad() bool {
method HasChanged (line 89) | func (c *C) HasChanged(k string) bool {
method CatchHUP (line 123) | func (c *C) CatchHUP(ctx context.Context) {
method ReloadConfig (line 146) | func (c *C) ReloadConfig() {
method ReloadConfigString (line 166) | func (c *C) ReloadConfigString(raw string) error {
method GetString (line 188) | func (c *C) GetString(k, d string) string {
method GetStringSlice (line 198) | func (c *C) GetStringSlice(k string, d []string) []string {
method GetMap (line 218) | func (c *C) GetMap(k string, d map[string]any) map[string]any {
method GetInt (line 233) | func (c *C) GetInt(k string, d int) int {
method GetUint32 (line 244) | func (c *C) GetUint32(k string, d uint32) uint32 {
method GetBool (line 253) | func (c *C) GetBool(k string, d bool) bool {
method GetDuration (line 286) | func (c *C) GetDuration(k string, d time.Duration) time.Duration {
method Get (line 295) | func (c *C) Get(k string) any {
method IsSet (line 299) | func (c *C) IsSet(k string) bool {
method get (line 303) | func (c *C) get(k string, v any) any {
method resolve (line 322) | func (c *C) resolve(path string, direct bool) error {
method addFile (line 348) | func (c *C) addFile(path string, direct bool) error {
method parseRaw (line 364) | func (c *C) parseRaw(b []byte) error {
method parse (line 376) | func (c *C) parse() error {
function NewC (line 33) | func NewC(l *logrus.Logger) *C {
function AsBool (line 269) | func AsBool(v any) (value bool, ok bool) {
function readDirNames (line 404) | func readDirNames(path string) ([]string, error) {
FILE: config/config_test.go
function TestConfig_Load (line 16) | func TestConfig_Load(t *testing.T) {
function TestConfig_Get (line 43) | func TestConfig_Get(t *testing.T) {
function TestConfig_GetStringSlice (line 59) | func TestConfig_GetStringSlice(t *testing.T) {
function TestConfig_GetBool (line 66) | func TestConfig_GetBool(t *testing.T) {
function TestConfig_HasChanged (line 94) | func TestConfig_HasChanged(t *testing.T) {
function TestConfig_ReloadConfig (line 116) | func TestConfig_ReloadConfig(t *testing.T) {
function TestConfig_MergoMerge (line 153) | func TestConfig_MergoMerge(t *testing.T) {
FILE: connection_manager.go
type trafficDecision (line 20) | type trafficDecision
constant doNothing (line 23) | doNothing trafficDecision = 0
constant deleteTunnel (line 24) | deleteTunnel trafficDecision = 1
constant closeTunnel (line 25) | closeTunnel trafficDecision = 2
constant swapPrimary (line 26) | swapPrimary trafficDecision = 3
constant migrateRelays (line 27) | migrateRelays trafficDecision = 4
constant tryRehandshake (line 28) | tryRehandshake trafficDecision = 5
constant sendTestPacket (line 29) | sendTestPacket trafficDecision = 6
type connectionManager (line 32) | type connectionManager struct
method reload (line 71) | func (cm *connectionManager) reload(c *config.C, initial bool) {
method getInactivityTimeout (line 105) | func (cm *connectionManager) getInactivityTimeout() time.Duration {
method In (line 109) | func (cm *connectionManager) In(h *HostInfo) {
method Out (line 113) | func (cm *connectionManager) Out(h *HostInfo) {
method RelayUsed (line 117) | func (cm *connectionManager) RelayUsed(localIndex uint32) {
method getAndResetTrafficCheck (line 132) | func (cm *connectionManager) getAndResetTrafficCheck(h *HostInfo, now ...
method AddTrafficWatch (line 143) | func (cm *connectionManager) AddTrafficWatch(h *HostInfo) {
method Start (line 149) | func (cm *connectionManager) Start(ctx context.Context) {
method doTrafficCheck (line 176) | func (cm *connectionManager) doTrafficCheck(localIndex uint32, p, nb, ...
method resetRelayTrafficCheck (line 206) | func (cm *connectionManager) resetRelayTrafficCheck(hostinfo *HostInfo) {
method migrateRelayUsed (line 217) | func (cm *connectionManager) migrateRelayUsed(oldhostinfo, newhostinfo...
method makeTrafficDecision (line 321) | func (cm *connectionManager) makeTrafficDecision(localIndex uint32, no...
method isInactive (line 433) | func (cm *connectionManager) isInactive(hostinfo *HostInfo, now time.T...
method shouldSwapPrimary (line 449) | func (cm *connectionManager) shouldSwapPrimary(current *HostInfo) bool {
method swapPrimary (line 472) | func (cm *connectionManager) swapPrimary(current, primary *HostInfo) {
method isInvalidCertificate (line 484) | func (cm *connectionManager) isInvalidCertificate(now time.Time, hosti...
method sendPunch (line 511) | func (cm *connectionManager) sendPunch(hostinfo *HostInfo) {
method tryRehandshake (line 536) | func (cm *connectionManager) tryRehandshake(hostinfo *HostInfo) {
function newConnectionManagerFromConfig (line 53) | func newConnectionManagerFromConfig(l *logrus.Logger, c *config.C, hm *H...
FILE: connection_manager_test.go
function newTestLighthouse (line 19) | func newTestLighthouse() *LightHouse {
function Test_NewConnectionManagerTest (line 34) | func Test_NewConnectionManagerTest(t *testing.T) {
function Test_NewConnectionManagerTest2 (line 117) | func Test_NewConnectionManagerTest2(t *testing.T) {
function Test_NewConnectionManager_DisconnectInactive (line 203) | func Test_NewConnectionManager_DisconnectInactive(t *testing.T) {
function Test_NewConnectionManagerTest_DisconnectInvalid (line 300) | func Test_NewConnectionManagerTest_DisconnectInvalid(t *testing.T) {
type dummyCert (line 394) | type dummyCert struct
method Version (line 409) | func (d *dummyCert) Version() cert.Version {
method Curve (line 413) | func (d *dummyCert) Curve() cert.Curve {
method Groups (line 417) | func (d *dummyCert) Groups() []string {
method IsCA (line 421) | func (d *dummyCert) IsCA() bool {
method Issuer (line 425) | func (d *dummyCert) Issuer() string {
method Name (line 429) | func (d *dummyCert) Name() string {
method Networks (line 433) | func (d *dummyCert) Networks() []netip.Prefix {
method NotAfter (line 437) | func (d *dummyCert) NotAfter() time.Time {
method NotBefore (line 441) | func (d *dummyCert) NotBefore() time.Time {
method PublicKey (line 445) | func (d *dummyCert) PublicKey() []byte {
method MarshalPublicKeyPEM (line 449) | func (d *dummyCert) MarshalPublicKeyPEM() []byte {
method Signature (line 453) | func (d *dummyCert) Signature() []byte {
method UnsafeNetworks (line 457) | func (d *dummyCert) UnsafeNetworks() []netip.Prefix {
method MarshalForHandshakes (line 461) | func (d *dummyCert) MarshalForHandshakes() ([]byte, error) {
method Sign (line 465) | func (d *dummyCert) Sign(curve cert.Curve, key []byte) error {
method CheckSignature (line 469) | func (d *dummyCert) CheckSignature(key []byte) bool {
method Expired (line 473) | func (d *dummyCert) Expired(t time.Time) bool {
method CheckRootConstraints (line 477) | func (d *dummyCert) CheckRootConstraints(signer cert.Certificate) error {
method VerifyPrivateKey (line 481) | func (d *dummyCert) VerifyPrivateKey(curve cert.Curve, key []byte) err...
method String (line 485) | func (d *dummyCert) String() string {
method Marshal (line 489) | func (d *dummyCert) Marshal() ([]byte, error) {
method MarshalPEM (line 493) | func (d *dummyCert) MarshalPEM() ([]byte, error) {
method Fingerprint (line 497) | func (d *dummyCert) Fingerprint() (string, error) {
method MarshalJSON (line 501) | func (d *dummyCert) MarshalJSON() ([]byte, error) {
method Copy (line 505) | func (d *dummyCert) Copy() cert.Certificate {
FILE: connection_state.go
constant ReplayWindow (line 16) | ReplayWindow = 1024
type ConnectionState (line 18) | type ConnectionState struct
method MarshalJSON (line 81) | func (cs *ConnectionState) MarshalJSON() ([]byte, error) {
method Curve (line 89) | func (cs *ConnectionState) Curve() cert.Curve {
function NewConnectionState (line 30) | func NewConnectionState(l *logrus.Logger, cs *CertState, crt cert.Certif...
FILE: control.go
type controlEach (line 19) | type controlEach
type controlHostLister (line 21) | type controlHostLister interface
type Control (line 28) | type Control struct
method Start (line 53) | func (c *Control) Start() {
method Context (line 78) | func (c *Control) Context() context.Context {
method Stop (line 83) | func (c *Control) Stop() {
method ShutdownBlock (line 96) | func (c *Control) ShutdownBlock() {
method RebindUDPServer (line 108) | func (c *Control) RebindUDPServer() {
method ListHostmapHosts (line 119) | func (c *Control) ListHostmapHosts(pendingMap bool) []ControlHostInfo {
method ListHostmapIndexes (line 128) | func (c *Control) ListHostmapIndexes(pendingMap bool) []ControlHostInfo {
method GetCertByVpnIp (line 137) | func (c *Control) GetCertByVpnIp(vpnIp netip.Addr) cert.Certificate {
method CreateTunnel (line 151) | func (c *Control) CreateTunnel(vpnIp netip.Addr) {
method PrintTunnel (line 156) | func (c *Control) PrintTunnel(vpnIp netip.Addr) *ControlHostInfo {
method QueryLighthouse (line 166) | func (c *Control) QueryLighthouse(vpnIp netip.Addr) *CacheMap {
method GetHostInfoByVpnAddr (line 176) | func (c *Control) GetHostInfoByVpnAddr(vpnAddr netip.Addr, pending boo...
method SetRemoteForTunnel (line 195) | func (c *Control) SetRemoteForTunnel(vpnIp netip.Addr, addr netip.Addr...
method CloseTunnel (line 208) | func (c *Control) CloseTunnel(vpnIp netip.Addr, localOnly bool) bool {
method CloseAllTunnels (line 232) | func (c *Control) CloseAllTunnels(excludeLighthouses bool) (closed int) {
method Device (line 273) | func (c *Control) Device() overlay.Device {
type ControlHostInfo (line 40) | type ControlHostInfo struct
function copyHostInfo (line 277) | func copyHostInfo(h *HostInfo, preferredRanges []netip.Prefix) ControlHo...
function listHostMapHosts (line 303) | func listHostMapHosts(hl controlHostLister) []ControlHostInfo {
function listHostMapIndexes (line 312) | func listHostMapIndexes(hl controlHostLister) []ControlHostInfo {
FILE: control_test.go
function TestControl_GetHostInfoByVpnIp (line 15) | func TestControl_GetHostInfoByVpnIp(t *testing.T) {
function assertFields (line 113) | func assertFields(t *testing.T, expected []string, actualStruct any) {
FILE: control_tester.go
method WaitForType (line 17) | func (c *Control) WaitForType(msgType header.MessageType, subType header...
method WaitForTypeByIndex (line 33) | func (c *Control) WaitForTypeByIndex(toIndex uint32, msgType header.Mess...
method InjectLightHouseAddr (line 49) | func (c *Control) InjectLightHouseAddr(vpnIp netip.Addr, toAddr netip.Ad...
method InjectRelays (line 65) | func (c *Control) InjectRelays(vpnIp netip.Addr, relayVpnIps []netip.Add...
method GetFromTun (line 76) | func (c *Control) GetFromTun(block bool) []byte {
method GetFromUDP (line 81) | func (c *Control) GetFromUDP(block bool) *udp.Packet {
method GetUDPTxChan (line 85) | func (c *Control) GetUDPTxChan() <-chan *udp.Packet {
method GetTunTxChan (line 89) | func (c *Control) GetTunTxChan() <-chan []byte {
method InjectUDPPacket (line 94) | func (c *Control) InjectUDPPacket(p *udp.Packet) {
method InjectTunUDPPacket (line 99) | func (c *Control) InjectTunUDPPacket(toAddr netip.Addr, toPort uint16, f...
method GetVpnAddrs (line 154) | func (c *Control) GetVpnAddrs() []netip.Addr {
method GetUDPAddr (line 158) | func (c *Control) GetUDPAddr() netip.AddrPort {
method KillPendingTunnel (line 162) | func (c *Control) KillPendingTunnel(vpnIp netip.Addr) bool {
method GetHostmap (line 172) | func (c *Control) GetHostmap() *HostMap {
method GetF (line 176) | func (c *Control) GetF() *Interface {
method GetCertState (line 180) | func (c *Control) GetCertState() *CertState {
method ReHandshake (line 184) | func (c *Control) ReHandshake(vpnIp netip.Addr) {
FILE: dist/windows/wintun/include/wintun.h
type _WINTUN_ADAPTER (line 39) | struct _WINTUN_ADAPTER
type _Must_inspect_result_ (line 59) | typedef _Must_inspect_result_
type _Must_inspect_result_ (line 75) | typedef _Must_inspect_result_
type WINTUN_LOGGER_LEVEL (line 118) | typedef enum
type _TUN_SESSION (line 161) | struct _TUN_SESSION
type _Must_inspect_result_ (line 174) | typedef _Must_inspect_result_
type _Must_inspect_result_ (line 218) | typedef _Must_inspect_result_
FILE: dns_server.go
type dnsRecords (line 23) | type dnsRecords struct
method Query (line 42) | func (d *dnsRecords) Query(q uint16, data string) netip.Addr {
method QueryCert (line 60) | func (d *dnsRecords) QueryCert(data string) string {
method Add (line 84) | func (d *dnsRecords) Add(host string, addresses []netip.Addr) {
method isSelfNebulaOrLocalhost (line 104) | func (d *dnsRecords) isSelfNebulaOrLocalhost(addr string) bool {
method parseQuery (line 119) | func (d *dnsRecords) parseQuery(m *dns.Msg, w dns.ResponseWriter) {
method handleDnsRequest (line 153) | func (d *dnsRecords) handleDnsRequest(w dns.ResponseWriter, r *dns.Msg) {
function newDnsRecords (line 32) | func newDnsRecords(l *logrus.Logger, cs *CertState, hostMap *HostMap) *d...
function dnsMain (line 166) | func dnsMain(l *logrus.Logger, cs *CertState, hostMap *HostMap, c *confi...
function getDnsServerAddr (line 181) | func getDnsServerAddr(c *config.C) string {
function startDns (line 190) | func startDns(l *logrus.Logger, c *config.C) {
function reloadDns (line 201) | func reloadDns(l *logrus.Logger, c *config.C) {
FILE: dns_server_test.go
function TestParsequery (line 13) | func TestParsequery(t *testing.T) {
function Test_getDnsServerAddr (line 38) | func Test_getDnsServerAddr(t *testing.T) {
FILE: e2e/handshakes_test.go
function BenchmarkHotPath (line 26) | func BenchmarkHotPath(b *testing.B) {
function BenchmarkHotPathRelay (line 54) | func BenchmarkHotPathRelay(b *testing.B) {
function TestGoodHandshake (line 87) | func TestGoodHandshake(t *testing.T) {
function TestGoodHandshakeNoOverlap (line 137) | func TestGoodHandshakeNoOverlap(t *testing.T) {
function TestWrongResponderHandshake (line 172) | func TestWrongResponderHandshake(t *testing.T) {
function TestWrongResponderHandshakeStaticHostMap (line 248) | func TestWrongResponderHandshakeStaticHostMap(t *testing.T) {
function TestStage1Race (line 330) | func TestStage1Race(t *testing.T) {
function TestUncleanShutdownRaceLoser (line 410) | func TestUncleanShutdownRaceLoser(t *testing.T) {
function TestUncleanShutdownRaceWinner (line 459) | func TestUncleanShutdownRaceWinner(t *testing.T) {
function TestRelays (line 510) | func TestRelays(t *testing.T) {
function TestRelaysDontCareAboutIps (line 539) | func TestRelaysDontCareAboutIps(t *testing.T) {
function TestReestablishRelays (line 568) | func TestReestablishRelays(t *testing.T) {
function TestStage1RaceRelays (line 699) | func TestStage1RaceRelays(t *testing.T) {
function TestStage1RaceRelays2 (line 746) | func TestStage1RaceRelays2(t *testing.T) {
function TestRehandshakingRelays (line 832) | func TestRehandshakingRelays(t *testing.T) {
function TestRehandshakingRelaysPrimary (line 935) | func TestRehandshakingRelaysPrimary(t *testing.T) {
function TestRehandshaking (line 1039) | func TestRehandshaking(t *testing.T) {
function TestRehandshakingLoser (line 1134) | func TestRehandshakingLoser(t *testing.T) {
function TestRaceRegression (line 1232) | func TestRaceRegression(t *testing.T) {
function TestV2NonPrimaryWithLighthouse (line 1292) | func TestV2NonPrimaryWithLighthouse(t *testing.T) {
function TestV2NonPrimaryWithOffNetLighthouse (line 1332) | func TestV2NonPrimaryWithOffNetLighthouse(t *testing.T) {
function TestGoodHandshakeUnsafeDest (line 1372) | func TestGoodHandshakeUnsafeDest(t *testing.T) {
FILE: e2e/helpers_test.go
function newSimpleServer (line 32) | func newSimpleServer(v cert.Version, caCrt cert.Certificate, caKey []byt...
function newSimpleServerWithUdp (line 61) | func newSimpleServerWithUdp(v cert.Version, caCrt cert.Certificate, caKe...
function newSimpleServerWithUdpAndUnsafeNetworks (line 65) | func newSimpleServerWithUdpAndUnsafeNetworks(v cert.Version, caCrt cert....
function newServer (line 175) | func newServer(caCrt []cert.Certificate, certs []cert.Certificate, key [...
type doneCb (line 277) | type doneCb
function deadline (line 279) | func deadline(t *testing.T, seconds time.Duration) doneCb {
function assertTunnel (line 295) | func assertTunnel(t testing.TB, vpnIpA, vpnIpB netip.Addr, controlA, con...
function assertHostInfoPair (line 307) | func assertHostInfoPair(t testing.TB, addrA, addrB netip.AddrPort, vpnNe...
function assertUdpPacket (line 328) | func assertUdpPacket(t testing.TB, expected, b []byte, fromIp, toIp neti...
function assertUdpPacket6 (line 336) | func assertUdpPacket6(t testing.TB, expected, b []byte, fromIp, toIp net...
function assertUdpPacket4 (line 355) | func assertUdpPacket4(t testing.TB, expected, b []byte, fromIp, toIp net...
function getAddrs (line 374) | func getAddrs(ns []netip.Prefix) []netip.Addr {
function NewTestLogger (line 382) | func NewTestLogger() *logrus.Logger {
FILE: e2e/router/hostmap.go
type edge (line 15) | type edge struct
function renderHostmaps (line 21) | func renderHostmaps(controls ...*nebula.Control) string {
function renderHostmap (line 57) | func renderHostmap(c *nebula.Control) (string, []*edge) {
function sortedHosts (line 122) | func sortedHosts(hosts map[netip.Addr]*nebula.HostInfo) []netip.Addr {
function sortedIndexes (line 135) | func sortedIndexes(indexes map[uint32]*nebula.HostInfo) []uint32 {
FILE: e2e/router/router.go
type R (line 27) | type R struct
method AddRoute (line 169) | func (r *R) AddRoute(ip netip.Addr, port uint16, c *nebula.Control) {
method RenderFlow (line 181) | func (r *R) RenderFlow() {
method CancelFlowLogs (line 187) | func (r *R) CancelFlowLogs() {
method renderFlow (line 192) | func (r *R) renderFlow() {
method IgnoreFlow (line 281) | func (r *R) IgnoreFlow(messageType header.MessageType, subType header....
method RenderHostmaps (line 291) | func (r *R) RenderHostmaps(title string, controls ...*nebula.Control) {
method renderHostmaps (line 311) | func (r *R) renderHostmaps(title string) {
method InjectFlow (line 335) | func (r *R) InjectFlow(from, to *nebula.Control, p *udp.Packet) {
method Log (line 341) | func (r *R) Log(arg ...any) {
method Logf (line 352) | func (r *R) Logf(format string, arg ...any) {
method unlockedInjectFlow (line 366) | func (r *R) unlockedInjectFlow(from, to *nebula.Control, p *udp.Packet...
method OnceFrom (line 404) | func (r *R) OnceFrom(sender *nebula.Control) {
method RouteUntilTxTun (line 412) | func (r *R) RouteUntilTxTun(sender *nebula.Control, receiver *nebula.C...
method RouteForAllUntilTxTun (line 446) | func (r *R) RouteForAllUntilTxTun(receiver *nebula.Control) []byte {
method RouteExitFunc (line 506) | func (r *R) RouteExitFunc(sender *nebula.Control, whatDo ExitFunc) {
method RouteUntilAfterMsgType (line 549) | func (r *R) RouteUntilAfterMsgType(sender *nebula.Control, msgType hea...
method RouteForAllUntilAfterMsgTypeTo (line 563) | func (r *R) RouteForAllUntilAfterMsgTypeTo(receiver *nebula.Control, m...
method InjectUDPPacket (line 582) | func (r *R) InjectUDPPacket(sender, receiver *nebula.Control, packet *...
method RouteForUntilAfterToAddr (line 594) | func (r *R) RouteForUntilAfterToAddr(sender *nebula.Control, toAddr ne...
method RouteForAllExitFunc (line 613) | func (r *R) RouteForAllExitFunc(whatDo ExitFunc) {
method FlushAll (line 666) | func (r *R) FlushAll() {
method getControl (line 710) | func (r *R) getControl(fromAddr, toAddr netip.AddrPort, p *udp.Packet)...
method formatUdpPacket (line 724) | func (r *R) formatUdpPacket(p *packet) string {
type ignoreFlow (line 58) | type ignoreFlow struct
type mermaidGraph (line 66) | type mermaidGraph struct
type NullBool (line 71) | type NullBool struct
type flowEntry (line 76) | type flowEntry struct
type packet (line 81) | type packet struct
method WasReceived (line 89) | func (p *packet) WasReceived() {
type ExitType (line 95) | type ExitType
constant KeepRouting (line 99) | KeepRouting ExitType = 0
constant ExitNow (line 101) | ExitNow ExitType = 1
constant RouteAndExit (line 103) | RouteAndExit ExitType = 2
type ExitFunc (line 106) | type ExitFunc
function NewR (line 111) | func NewR(t testing.TB, controls ...*nebula.Control) *R {
function normalizeName (line 273) | func normalizeName(s string) string {
FILE: e2e/tunnels_test.go
function TestDropInactiveTunnels (line 19) | func TestDropInactiveTunnels(t *testing.T) {
function TestCertUpgrade (line 63) | func TestCertUpgrade(t *testing.T) {
function TestCertDowngrade (line 157) | func TestCertDowngrade(t *testing.T) {
function TestCertMismatchCorrection (line 255) | func TestCertMismatchCorrection(t *testing.T) {
function TestCrossStackRelaysWork (line 322) | func TestCrossStackRelaysWork(t *testing.T) {
FILE: examples/go_service/main.go
function main (line 17) | func main() {
function run (line 23) | func run() error {
FILE: firewall.go
type FirewallInterface (line 25) | type FirewallInterface interface
type conn (line 29) | type conn struct
type Firewall (line 40) | type Firewall struct
method AddRule (line 251) | func (f *Firewall) AddRule(incoming bool, proto uint8, startPort int32...
method GetRuleHash (line 300) | func (f *Firewall) GetRuleHash() string {
method GetRuleHashFNV (line 306) | func (f *Firewall) GetRuleHashFNV() uint32 {
method GetRuleHashes (line 313) | func (f *Firewall) GetRuleHashes() string {
method Drop (line 419) | func (f *Firewall) Drop(fp firewall.Packet, incoming bool, h *HostInfo...
method metrics (line 475) | func (f *Firewall) metrics(incoming bool) firewallMetrics {
method Destroy (line 485) | func (f *Firewall) Destroy() {
method EmitStats (line 489) | func (f *Firewall) EmitStats() {
method inConns (line 499) | func (f *Firewall) inConns(fp firewall.Packet, h *HostInfo, caPool *ce...
method addConn (line 574) | func (f *Firewall) addConn(fp firewall.Packet, incoming bool) {
method evict (line 605) | func (f *Firewall) evict(p firewall.Packet) {
type firewallMetrics (line 73) | type firewallMetrics struct
type FirewallConntrack (line 79) | type FirewallConntrack struct
type FirewallTable (line 88) | type FirewallTable struct
method match (line 626) | func (ft *FirewallTable) match(p firewall.Packet, incoming bool, c *ce...
function newFirewallTable (line 95) | func newFirewallTable() *FirewallTable {
type FirewallCA (line 104) | type FirewallCA struct
method addRule (line 700) | func (fc *FirewallCA) addRule(f *Firewall, groups []string, host strin...
method match (line 740) | func (fc *FirewallCA) match(p firewall.Packet, c *cert.CachedCertifica...
type FirewallRule (line 110) | type FirewallRule struct
method addRule (line 763) | func (fr *FirewallRule) addRule(f *Firewall, groups []string, host, ci...
method isAny (line 822) | func (fr *FirewallRule) isAny(groups []string, host string, cidr strin...
method match (line 842) | func (fr *FirewallRule) match(p firewall.Packet, c *cert.CachedCertifi...
type firewallGroups (line 118) | type firewallGroups struct
type firewallPort (line 125) | type firewallPort
method addRule (line 649) | func (fp firewallPort) addRule(f *Firewall, startPort int32, endPort i...
method match (line 670) | func (fp firewallPort) match(p firewall.Packet, incoming bool, c *cert...
type firewallLocalCIDR (line 127) | type firewallLocalCIDR struct
method addRule (line 887) | func (flc *firewallLocalCIDR) addRule(f *Firewall, localCidr string) e...
method match (line 914) | func (flc *firewallLocalCIDR) match(p firewall.Packet, c *cert.CachedC...
function NewFirewall (line 134) | func NewFirewall(l *logrus.Logger, tcpTimeout, UDPTimeout, defaultTimeou...
function NewFirewallFromConfig (line 194) | func NewFirewallFromConfig(l *logrus.Logger, cs *CertState, c *config.C)...
function AddFirewallRulesFromConfig (line 317) | func AddFirewallRulesFromConfig(l *logrus.Logger, inbound bool, c *confi...
type rule (line 926) | type rule struct
method sanity (line 1004) | func (r *rule) sanity() error {
function convertRule (line 938) | func convertRule(l *logrus.Logger, p any, table string, i int) (rule, er...
function parsePort (line 1048) | func parsePort(s string) (int32, int32, error) {
FILE: firewall/cache.go
type ConntrackCache (line 12) | type ConntrackCache
type ConntrackCacheTicker (line 14) | type ConntrackCacheTicker struct
method tick (line 35) | func (c *ConntrackCacheTicker) tick(d time.Duration) {
method Get (line 44) | func (c *ConntrackCacheTicker) Get(l *logrus.Logger) ConntrackCache {
function NewConntrackCacheTicker (line 21) | func NewConntrackCacheTicker(d time.Duration) *ConntrackCacheTicker {
FILE: firewall/packet.go
constant ProtoAny (line 12) | ProtoAny = 0
constant ProtoTCP (line 13) | ProtoTCP = 6
constant ProtoUDP (line 14) | ProtoUDP = 17
constant ProtoICMP (line 15) | ProtoICMP = 1
constant ProtoICMPv6 (line 16) | ProtoICMPv6 = 58
constant PortAny (line 18) | PortAny = 0
constant PortFragment (line 19) | PortFragment = -1
type Packet (line 22) | type Packet struct
method Copy (line 34) | func (fp *Packet) Copy() *Packet {
method MarshalJSON (line 45) | func (fp Packet) MarshalJSON() ([]byte, error) {
FILE: firewall_test.go
function TestNewFirewall (line 21) | func TestNewFirewall(t *testing.T) {
function TestFirewall_AddRule (line 60) | func TestFirewall_AddRule(t *testing.T) {
function TestFirewall_Drop (line 179) | func TestFirewall_Drop(t *testing.T) {
function TestFirewall_DropV6 (line 256) | func TestFirewall_DropV6(t *testing.T) {
function BenchmarkFirewallTable_match (line 335) | func BenchmarkFirewallTable_match(b *testing.B) {
function TestFirewall_Drop2 (line 487) | func TestFirewall_Drop2(t *testing.T) {
function TestFirewall_Drop3 (line 546) | func TestFirewall_Drop3(t *testing.T) {
function TestFirewall_Drop3V6 (line 635) | func TestFirewall_Drop3V6(t *testing.T) {
function TestFirewall_DropConntrackReload (line 673) | func TestFirewall_DropConntrackReload(t *testing.T) {
function TestFirewall_ICMPPortBehavior (line 738) | func TestFirewall_ICMPPortBehavior(t *testing.T) {
function TestFirewall_DropIPSpoofing (line 882) | func TestFirewall_DropIPSpoofing(t *testing.T) {
function BenchmarkLookup (line 928) | func BenchmarkLookup(b *testing.B) {
function Test_parsePort (line 1001) | func Test_parsePort(t *testing.T) {
function TestNewFirewallFromConfig (line 1041) | func TestNewFirewallFromConfig(t *testing.T) {
function TestAddFirewallRulesFromConfig (line 1100) | func TestAddFirewallRulesFromConfig(t *testing.T) {
function TestFirewall_convertRule (line 1236) | func TestFirewall_convertRule(t *testing.T) {
function TestFirewall_convertRuleSanity (line 1272) | func TestFirewall_convertRuleSanity(t *testing.T) {
type testcase (line 1328) | type testcase struct
method Test (line 1335) | func (c *testcase) Test(t *testing.T, fw *Firewall) {
function buildTestCase (line 1347) | func buildTestCase(setup testsetup, err error, theirPrefixes ...netip.Pr...
type testsetup (line 1383) | type testsetup struct
function newSetup (line 1389) | func newSetup(t *testing.T, l *logrus.Logger, myPrefixes ...netip.Prefix...
function newSetupFromCert (line 1400) | func newSetupFromCert(t *testing.T, l *logrus.Logger, c dummyCert) tests...
function TestFirewall_Drop_EnforceIPMatch (line 1415) | func TestFirewall_Drop_EnforceIPMatch(t *testing.T) {
type addRuleCall (line 1493) | type addRuleCall struct
type mockFirewall (line 1506) | type mockFirewall struct
method AddRule (line 1511) | func (mf *mockFirewall) AddRule(incoming bool, proto uint8, startPort ...
function resetConntrack (line 1530) | func resetConntrack(fw *Firewall) {
FILE: handshake_ix.go
function ixHandshakeStage0 (line 18) | func ixHandshakeStage0(f *Interface, hh *HandshakeHostInfo) bool {
function ixHandshakeStage1 (line 103) | func ixHandshakeStage1(f *Interface, via ViaSender, packet []byte, h *he...
function ixHandshakeStage2 (line 468) | func ixHandshakeStage2(f *Interface, via ViaSender, hh *HandshakeHostInf...
FILE: handshake_manager.go
constant DefaultHandshakeTryInterval (line 22) | DefaultHandshakeTryInterval = time.Millisecond * 100
constant DefaultHandshakeRetries (line 23) | DefaultHandshakeRetries = 10
constant DefaultHandshakeTriggerBuffer (line 24) | DefaultHandshakeTriggerBuffer = 64
constant DefaultUseRelays (line 25) | DefaultUseRelays = true
type HandshakeConfig (line 37) | type HandshakeConfig struct
type HandshakeManager (line 46) | type HandshakeManager struct
method Run (line 123) | func (hm *HandshakeManager) Run(ctx context.Context) {
method HandleIncoming (line 139) | func (hm *HandshakeManager) HandleIncoming(via ViaSender, packet []byt...
method NextOutboundHandshakeTimerTick (line 164) | func (hm *HandshakeManager) NextOutboundHandshakeTimerTick(now time.Ti...
method handleOutbound (line 175) | func (hm *HandshakeManager) handleOutbound(vpnIp netip.Addr, lighthous...
method GetOrHandshake (line 421) | func (hm *HandshakeManager) GetOrHandshake(vpnIp netip.Addr, cacheCb f...
method StartHandshake (line 438) | func (hm *HandshakeManager) StartHandshake(vpnAddr netip.Addr, cacheCb...
method CheckAndComplete (line 509) | func (hm *HandshakeManager) CheckAndComplete(hostinfo *HostInfo, hands...
method Complete (line 564) | func (hm *HandshakeManager) Complete(hostinfo *HostInfo, f *Interface) {
method allocateIndex (line 587) | func (hm *HandshakeManager) allocateIndex(hh *HandshakeHostInfo) error {
method DeleteHostInfo (line 612) | func (hm *HandshakeManager) DeleteHostInfo(hostinfo *HostInfo) {
method unlockedDeleteHostInfo (line 618) | func (hm *HandshakeManager) unlockedDeleteHostInfo(hostinfo *HostInfo) {
method QueryVpnAddr (line 639) | func (hm *HandshakeManager) QueryVpnAddr(vpnIp netip.Addr) *HostInfo {
method queryVpnIp (line 648) | func (hm *HandshakeManager) queryVpnIp(vpnIp netip.Addr) *HandshakeHos...
method QueryIndex (line 654) | func (hm *HandshakeManager) QueryIndex(index uint32) *HostInfo {
method queryIndex (line 662) | func (hm *HandshakeManager) queryIndex(index uint32) *HandshakeHostInfo {
method GetPreferredRanges (line 668) | func (hm *HandshakeManager) GetPreferredRanges() []netip.Prefix {
method ForEachVpnAddr (line 672) | func (hm *HandshakeManager) ForEachVpnAddr(f controlEach) {
method ForEachIndex (line 681) | func (hm *HandshakeManager) ForEachIndex(f controlEach) {
method EmitStats (line 690) | func (hm *HandshakeManager) EmitStats() {
type HandshakeHostInfo (line 68) | type HandshakeHostInfo struct
method cachePacket (line 81) | func (hh *HandshakeHostInfo) cachePacket(l *logrus.Logger, t header.Me...
function NewHandshakeManager (line 106) | func NewHandshakeManager(l *logrus.Logger, mainHostMap *HostMap, lightHo...
function generateIndex (line 703) | func generateIndex(l *logrus.Logger) (uint32, error) {
function hsTimeout (line 725) | func hsTimeout(tries int64, interval time.Duration) time.Duration {
FILE: handshake_manager_test.go
function Test_NewHandshakeManagerVpnIp (line 15) | func Test_NewHandshakeManagerVpnIp(t *testing.T) {
function testCountTimerWheelEntries (line 68) | func testCountTimerWheelEntries(tw *LockingTimerWheel[netip.Addr]) (c in...
type mockEncWriter (line 79) | type mockEncWriter struct
method SendMessageToVpnAddr (line 82) | func (mw *mockEncWriter) SendMessageToVpnAddr(_ header.MessageType, _ ...
method SendVia (line 86) | func (mw *mockEncWriter) SendVia(_ *HostInfo, _ *Relay, _, _, _ []byte...
method SendMessageToHostInfo (line 90) | func (mw *mockEncWriter) SendMessageToHostInfo(_ header.MessageType, _...
method Handshake (line 94) | func (mw *mockEncWriter) Handshake(_ netip.Addr) {}
method GetHostInfo (line 96) | func (mw *mockEncWriter) GetHostInfo(_ netip.Addr) *HostInfo {
method GetCertState (line 100) | func (mw *mockEncWriter) GetCertState() *CertState {
FILE: header/header.go
constant Version (line 25) | Version uint8 = 1
constant Len (line 26) | Len = 16
type MessageType (line 29) | type MessageType
type MessageSubType (line 30) | type MessageSubType
constant Handshake (line 33) | Handshake MessageType = 0
constant Message (line 34) | Message MessageType = 1
constant RecvError (line 35) | RecvError MessageType = 2
constant LightHouse (line 36) | LightHouse MessageType = 3
constant Test (line 37) | Test MessageType = 4
constant CloseTunnel (line 38) | CloseTunnel MessageType = 5
constant Control (line 39) | Control MessageType = 6
constant MessageNone (line 53) | MessageNone MessageSubType = 0
constant MessageRelay (line 54) | MessageRelay MessageSubType = 1
constant TestRequest (line 58) | TestRequest MessageSubType = 0
constant TestReply (line 59) | TestReply MessageSubType = 1
constant HandshakeIXPSK0 (line 63) | HandshakeIXPSK0 MessageSubType = 0
constant HandshakeXXPSK0 (line 64) | HandshakeXXPSK0 MessageSubType = 1
type H (line 91) | type H struct
method String (line 113) | func (h *H) String() string {
method MarshalJSON (line 122) | func (h *H) MarshalJSON() ([]byte, error) {
method Encode (line 134) | func (h *H) Encode(b []byte) ([]byte, error) {
method Parse (line 143) | func (h *H) Parse(b []byte) error {
method TypeName (line 159) | func (h *H) TypeName() string {
method SubTypeName (line 173) | func (h *H) SubTypeName() string {
function Encode (line 102) | func Encode(b []byte, v uint8, t MessageType, st MessageSubType, ri uint...
function TypeName (line 164) | func TypeName(t MessageType) string {
function SubTypeName (line 178) | func SubTypeName(t MessageType, s MessageSubType) string {
function NewHeader (line 189) | func NewHeader(b []byte) (*H, error) {
FILE: header/header_test.go
type headerTest (line 11) | type headerTest struct
function TestEncode (line 32) | func TestEncode(t *testing.T) {
function TestParse (line 43) | func TestParse(t *testing.T) {
function TestTypeName (line 55) | func TestTypeName(t *testing.T) {
function TestSubTypeName (line 63) | func TestSubTypeName(t *testing.T) {
function TestTypeMap (line 77) | func TestTypeMap(t *testing.T) {
function TestHeader_String (line 105) | func TestHeader_String(t *testing.T) {
function TestHeader_MarshalJSON (line 113) | func TestHeader_MarshalJSON(t *testing.T) {
FILE: hostmap.go
constant defaultPromoteEvery (line 22) | defaultPromoteEvery = 1000
constant defaultReQueryEvery (line 23) | defaultReQueryEvery = 5000
constant defaultReQueryWait (line 24) | defaultReQueryWait = time.Minute
constant MaxRemotes (line 25) | MaxRemotes = 10
constant MaxHostInfosPerVpnIp (line 29) | MaxHostInfosPerVpnIp = 5
constant RoamingSuppressSeconds (line 33) | RoamingSuppressSeconds = 2
constant Requested (line 36) | Requested = iota
constant PeerRequested (line 37) | PeerRequested
constant Established (line 38) | Established
constant Disestablished (line 39) | Disestablished
constant Unknowntype (line 43) | Unknowntype = iota
constant ForwardingType (line 44) | ForwardingType
constant TerminalType (line 45) | TerminalType
type Relay (line 48) | type Relay struct
type HostMap (line 56) | type HostMap struct
method reload (line 340) | func (hm *HostMap) reload(c *config.C, initial bool) {
method EmitStats (line 364) | func (hm *HostMap) EmitStats() {
method DeleteHostInfo (line 379) | func (hm *HostMap) DeleteHostInfo(hostinfo *HostInfo) bool {
method MakePrimary (line 390) | func (hm *HostMap) MakePrimary(hostinfo *HostInfo) {
method unlockedMakePrimary (line 396) | func (hm *HostMap) unlockedMakePrimary(hostinfo *HostInfo) {
method unlockedDeleteHostInfo (line 433) | func (hm *HostMap) unlockedDeleteHostInfo(hostinfo *HostInfo) {
method unlockedInnerDeleteHostInfo (line 445) | func (hm *HostMap) unlockedInnerDeleteHostInfo(hostinfo *HostInfo, add...
method QueryIndex (line 508) | func (hm *HostMap) QueryIndex(index uint32) *HostInfo {
method QueryRelayIndex (line 519) | func (hm *HostMap) QueryRelayIndex(index uint32) *HostInfo {
method QueryReverseIndex (line 530) | func (hm *HostMap) QueryReverseIndex(index uint32) *HostInfo {
method QueryVpnAddr (line 541) | func (hm *HostMap) QueryVpnAddr(vpnIp netip.Addr) *HostInfo {
method QueryVpnAddrsRelayFor (line 545) | func (hm *HostMap) QueryVpnAddrsRelayFor(targetIps []netip.Addr, relay...
method unlockedDisestablishVpnAddrRelayFor (line 567) | func (hm *HostMap) unlockedDisestablishVpnAddrRelayFor(hi *HostInfo) {
method queryVpnAddr (line 588) | func (hm *HostMap) queryVpnAddr(vpnIp netip.Addr, promoteIfce *Interfa...
method unlockedAddHostInfo (line 606) | func (hm *HostMap) unlockedAddHostInfo(hostinfo *HostInfo, f *Interfac...
method unlockedInnerAddHostInfo (line 625) | func (hm *HostMap) unlockedInnerAddHostInfo(vpnAddr netip.Addr, hostin...
method GetPreferredRanges (line 645) | func (hm *HostMap) GetPreferredRanges() []netip.Prefix {
method ForEachVpnAddr (line 650) | func (hm *HostMap) ForEachVpnAddr(f controlEach) {
method ForEachIndex (line 659) | func (hm *HostMap) ForEachIndex(f controlEach) {
type RelayState (line 69) | type RelayState struct
method DeleteRelay (line 80) | func (rs *RelayState) DeleteRelay(ip netip.Addr) {
method UpdateRelayForByIpState (line 91) | func (rs *RelayState) UpdateRelayForByIpState(vpnIp netip.Addr, state ...
method UpdateRelayForByIdxState (line 102) | func (rs *RelayState) UpdateRelayForByIdxState(idx uint32, state int) {
method CopyAllRelayFor (line 113) | func (rs *RelayState) CopyAllRelayFor() []*Relay {
method GetRelayForByAddr (line 123) | func (rs *RelayState) GetRelayForByAddr(addr netip.Addr) (*Relay, bool) {
method InsertRelayTo (line 130) | func (rs *RelayState) InsertRelayTo(ip netip.Addr) {
method CopyRelayIps (line 138) | func (rs *RelayState) CopyRelayIps() []netip.Addr {
method CopyRelayForIps (line 146) | func (rs *RelayState) CopyRelayForIps() []netip.Addr {
method CopyRelayForIdxs (line 156) | func (rs *RelayState) CopyRelayForIdxs() []uint32 {
method CompleteRelayByIP (line 166) | func (rs *RelayState) CompleteRelayByIP(vpnIp netip.Addr, remoteIdx ui...
method CompleteRelayByIdx (line 181) | func (rs *RelayState) CompleteRelayByIdx(localIdx uint32, remoteIdx ui...
method QueryRelayForByIp (line 196) | func (rs *RelayState) QueryRelayForByIp(vpnIp netip.Addr) (*Relay, boo...
method QueryRelayForByIdx (line 203) | func (rs *RelayState) QueryRelayForByIdx(idx uint32) (*Relay, bool) {
method InsertRelay (line 210) | func (rs *RelayState) InsertRelay(ip netip.Addr, idx uint32, r *Relay) {
type NetworkType (line 217) | type NetworkType
constant NetworkTypeUnknown (line 220) | NetworkTypeUnknown NetworkType = iota
constant NetworkTypeVPN (line 222) | NetworkTypeVPN
constant NetworkTypeVPNPeer (line 224) | NetworkTypeVPNPeer
constant NetworkTypeUnsafe (line 226) | NetworkTypeUnsafe
type HostInfo (line 229) | type HostInfo struct
method TryPromoteBest (line 670) | func (i *HostInfo) TryPromoteBest(preferredRanges []netip.Prefix, ifce...
method GetCert (line 708) | func (i *HostInfo) GetCert() *cert.CachedCertificate {
method SetRemote (line 716) | func (i *HostInfo) SetRemote(remote netip.AddrPort) {
method SetRemoteIfPreferred (line 726) | func (i *HostInfo) SetRemoteIfPreferred(hm *HostMap, via ViaSender) bo...
method buildNetworks (line 765) | func (i *HostInfo) buildNetworks(myVpnNetworksTable *bart.Lite, c cert...
method logger (line 787) | func (i *HostInfo) logger(l *logrus.Logger) *logrus.Entry {
type ViaSender (line 280) | type ViaSender struct
method String (line 288) | func (v ViaSender) String() string {
method MarshalJSON (line 295) | func (v ViaSender) MarshalJSON() ([]byte, error) {
type cachedPacket (line 302) | type cachedPacket struct
type packetCallback (line 309) | type packetCallback
type cachedPacketMetrics (line 311) | type cachedPacketMetrics struct
function NewHostMapFromConfig (line 316) | func NewHostMapFromConfig(l *logrus.Logger, c *config.C) *HostMap {
function newHostMap (line 330) | func newHostMap(l *logrus.Logger) *HostMap {
function localAddrs (line 807) | func localAddrs(l *logrus.Logger, allowList *LocalAllowList) []netip.Addr {
FILE: hostmap_test.go
function TestHostMap_MakePrimary (line 13) | func TestHostMap_MakePrimary(t *testing.T) {
function TestHostMap_DeleteHostInfo (line 87) | func TestHostMap_DeleteHostInfo(t *testing.T) {
function TestHostMap_reload (line 197) | func TestHostMap_reload(t *testing.T) {
function TestHostMap_RelayState (line 220) | func TestHostMap_RelayState(t *testing.T) {
FILE: hostmap_tester.go
method GetVpnAddrs (line 11) | func (i *HostInfo) GetVpnAddrs() []netip.Addr {
method GetLocalIndex (line 15) | func (i *HostInfo) GetLocalIndex() uint32 {
method GetRemoteIndex (line 19) | func (i *HostInfo) GetRemoteIndex() uint32 {
method GetRelayState (line 23) | func (i *HostInfo) GetRelayState() *RelayState {
FILE: inside.go
method consumeInsidePacket (line 14) | func (f *Interface) consumeInsidePacket(packet []byte, fwPacket *firewal...
method rejectInside (line 84) | func (f *Interface) rejectInside(packet []byte, out []byte, q int) {
method rejectOutside (line 100) | func (f *Interface) rejectOutside(packet []byte, ci *ConnectionState, ho...
method Handshake (line 125) | func (f *Interface) Handshake(vpnAddr netip.Addr) {
method getOrHandshakeNoRouting (line 131) | func (f *Interface) getOrHandshakeNoRouting(vpnAddr netip.Addr, cacheCal...
method getOrHandshakeConsiderRouting (line 141) | func (f *Interface) getOrHandshakeConsiderRouting(fwPacket *firewall.Pac...
method sendMessageNow (line 212) | func (f *Interface) sendMessageNow(t header.MessageType, st header.Messa...
method SendMessageToVpnAddr (line 236) | func (f *Interface) SendMessageToVpnAddr(t header.MessageType, st header...
method SendMessageToHostInfo (line 256) | func (f *Interface) SendMessageToHostInfo(t header.MessageType, st heade...
method send (line 260) | func (f *Interface) send(t header.MessageType, st header.MessageSubType,...
method sendTo (line 265) | func (f *Interface) sendTo(t header.MessageType, st header.MessageSubTyp...
method SendVia (line 278) | func (f *Interface) SendVia(via *HostInfo,
method sendNoMetrics (line 335) | func (f *Interface) sendNoMetrics(t header.MessageType, st header.Messag...
FILE: inside_bsd.go
constant immediatelyForwardToSelf (line 5) | immediatelyForwardToSelf bool = true
FILE: inside_generic.go
constant immediatelyForwardToSelf (line 5) | immediatelyForwardToSelf bool = false
FILE: interface.go
constant mtu (line 24) | mtu = 9001
type InterfaceConfig (line 26) | type InterfaceConfig struct
type Interface (line 53) | type Interface struct
method activate (line 213) | func (f *Interface) activate() {
method run (line 253) | func (f *Interface) run() {
method listenOut (line 265) | func (f *Interface) listenOut(i int) {
method listenIn (line 287) | func (f *Interface) listenIn(reader io.ReadWriteCloser, i int) {
method RegisterConfigChangeCallbacks (line 313) | func (f *Interface) RegisterConfigChangeCallbacks(c *config.C) {
method reloadDisconnectInvalid (line 325) | func (f *Interface) reloadDisconnectInvalid(c *config.C) {
method reloadFirewall (line 335) | func (f *Interface) reloadFirewall(c *config.C) {
method reloadSendRecvError (line 374) | func (f *Interface) reloadSendRecvError(c *config.C) {
method reloadAcceptRecvError (line 398) | func (f *Interface) reloadAcceptRecvError(c *config.C) {
method reloadMisc (line 422) | func (f *Interface) reloadMisc(c *config.C) {
method emitStats (line 442) | func (f *Interface) emitStats(ctx context.Context, i time.Duration) {
method GetHostInfo (line 476) | func (f *Interface) GetHostInfo(vpnIp netip.Addr) *HostInfo {
method GetCertState (line 480) | func (f *Interface) GetCertState() *CertState {
method Close (line 484) | func (f *Interface) Close() error {
type EncWriter (line 99) | type EncWriter interface
type recvErrorConfig (line 114) | type recvErrorConfig
method ShouldRecvError (line 122) | func (s recvErrorConfig) ShouldRecvError(endpoint netip.AddrPort) bool {
method String (line 135) | func (s recvErrorConfig) String() string {
constant recvErrorAlways (line 117) | recvErrorAlways recvErrorConfig = iota
constant recvErrorNever (line 118) | recvErrorNever
constant recvErrorPrivate (line 119) | recvErrorPrivate
function NewInterface (line 148) | func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, ...
FILE: iputil/packet.go
constant MaxRejectPacketSize (line 14) | MaxRejectPacketSize = ipv4.HeaderLen + 8 + 60 + 8
function CreateRejectPacket (line 17) | func CreateRejectPacket(packet []byte, out []byte) []byte {
function ipv4CreateRejectICMPPacket (line 30) | func ipv4CreateRejectICMPPacket(packet []byte, out []byte) []byte {
function ipv4CreateRejectTCPPacket (line 92) | func ipv4CreateRejectTCPPacket(packet []byte, out []byte) []byte {
function CreateICMPEchoResponse (line 168) | func CreateICMPEchoResponse(packet, out []byte) []byte {
function tcpipChecksum (line 207) | func tcpipChecksum(data []byte, csum uint32) uint16 {
function ipv4PseudoheaderChecksum (line 229) | func ipv4PseudoheaderChecksum(src, dst []byte, proto, length uint32) (cs...
FILE: iputil/packet_test.go
function Test_CreateRejectPacket (line 11) | func Test_CreateRejectPacket(t *testing.T) {
FILE: lighthouse.go
type LightHouse (line 29) | type LightHouse struct
method GetStaticHostList (line 143) | func (lh *LightHouse) GetStaticHostList() map[netip.Addr]struct{} {
method GetLighthouses (line 147) | func (lh *LightHouse) GetLighthouses() []netip.Addr {
method GetRemoteAllowList (line 151) | func (lh *LightHouse) GetRemoteAllowList() *RemoteAllowList {
method GetLocalAllowList (line 155) | func (lh *LightHouse) GetLocalAllowList() *LocalAllowList {
method GetAdvertiseAddrs (line 159) | func (lh *LightHouse) GetAdvertiseAddrs() []netip.AddrPort {
method GetRelaysForMe (line 163) | func (lh *LightHouse) GetRelaysForMe() []netip.Addr {
method getCalculatedRemotes (line 167) | func (lh *LightHouse) getCalculatedRemotes() *bart.Table[[]*calculated...
method GetUpdateInterval (line 171) | func (lh *LightHouse) GetUpdateInterval() int64 {
method reload (line 175) | func (lh *LightHouse) reload(c *config.C, initial bool) error {
method parseLighthouses (line 349) | func (lh *LightHouse) parseLighthouses(c *config.C) ([]netip.Addr, err...
method loadStaticMap (line 409) | func (lh *LightHouse) loadStaticMap(c *config.C, staticList map[netip....
method Query (line 458) | func (lh *LightHouse) Query(vpnAddr netip.Addr) *RemoteList {
method QueryServer (line 472) | func (lh *LightHouse) QueryServer(vpnAddr netip.Addr) {
method QueryCache (line 481) | func (lh *LightHouse) QueryCache(vpnAddrs []netip.Addr) *RemoteList {
method queryAndPrepMessage (line 498) | func (lh *LightHouse) queryAndPrepMessage(vpnAddr netip.Addr, f func(*...
method DeleteVpnAddrs (line 524) | func (lh *LightHouse) DeleteVpnAddrs(allVpnAddrs []netip.Addr) {
method addStaticRemotes (line 554) | func (lh *LightHouse) addStaticRemotes(i int, d time.Duration, network...
method addCalculatedRemotes (line 594) | func (lh *LightHouse) addCalculatedRemotes(vpnAddr netip.Addr) bool {
method unlockedGetRemoteList (line 638) | func (lh *LightHouse) unlockedGetRemoteList(allAddrs []netip.Addr) *Re...
method shouldAdd (line 657) | func (lh *LightHouse) shouldAdd(vpnAddrs []netip.Addr, to netip.Addr) ...
method unlockedShouldAddV4 (line 675) | func (lh *LightHouse) unlockedShouldAddV4(vpnAddr netip.Addr, to *V4Ad...
method unlockedShouldAddV6 (line 695) | func (lh *LightHouse) unlockedShouldAddV6(vpnAddr netip.Addr, to *V6Ad...
method IsLighthouseAddr (line 714) | func (lh *LightHouse) IsLighthouseAddr(vpnAddr netip.Addr) bool {
method IsAnyLighthouseAddr (line 719) | func (lh *LightHouse) IsAnyLighthouseAddr(vpnAddrs []netip.Addr) bool {
method startQueryWorker (line 729) | func (lh *LightHouse) startQueryWorker() {
method innerQueryServer (line 749) | func (lh *LightHouse) innerQueryServer(addr netip.Addr, nb, out []byte) {
method StartUpdateWorker (line 823) | func (lh *LightHouse) StartUpdateWorker() {
method SendUpdate (line 849) | func (lh *LightHouse) SendUpdate() {
method NewRequestHandler (line 973) | func (lh *LightHouse) NewRequestHandler() *LightHouseHandler {
method metricRx (line 989) | func (lh *LightHouse) metricRx(t NebulaMeta_MessageType, i int64) {
method metricTx (line 993) | func (lh *LightHouse) metricTx(t NebulaMeta_MessageType, i int64) {
function NewLightHouseFromConfig (line 83) | func NewLightHouseFromConfig(ctx context.Context, l *logrus.Logger, c *c...
function getStaticMapCadence (line 383) | func getStaticMapCadence(c *config.C) (time.Duration, error) {
function getStaticMapLookupTimeout (line 392) | func getStaticMapLookupTimeout(c *config.C) (time.Duration, error) {
function getStaticMapNetwork (line 401) | func getStaticMapNetwork(c *config.C) (string, error) {
type LightHouseHandler (line 964) | type LightHouseHandler struct
method resetMeta (line 999) | func (lhh *LightHouseHandler) resetMeta() *NebulaMeta {
method HandleRequest (line 1015) | func (lhh *LightHouseHandler) HandleRequest(rAddr netip.AddrPort, from...
method handleHostQuery (line 1051) | func (lhh *LightHouseHandler) handleHostQuery(n *NebulaMeta, fromVpnAd...
method sendHostPunchNotification (line 1108) | func (lhh *LightHouseHandler) sendHostPunchNotification(n *NebulaMeta,...
method coalesceAnswers (line 1160) | func (lhh *LightHouseHandler) coalesceAnswers(v cert.Version, c *cache...
method handleHostQueryReply (line 1201) | func (lhh *LightHouseHandler) handleHostQueryReply(n *NebulaMeta, from...
method handleHostUpdateNotification (line 1232) | func (lhh *LightHouseHandler) handleHostUpdateNotification(n *NebulaMe...
method handleHostPunchNotification (line 1303) | func (lhh *LightHouseHandler) handleHostPunchNotification(n *NebulaMet...
function protoAddrToNetAddr (line 1367) | func protoAddrToNetAddr(addr *Addr) netip.Addr {
function protoV4AddrPortToNetAddrPort (line 1374) | func protoV4AddrPortToNetAddrPort(ap *V4AddrPort) netip.AddrPort {
function protoV6AddrPortToNetAddrPort (line 1380) | func protoV6AddrPortToNetAddrPort(ap *V6AddrPort) netip.AddrPort {
function netAddrToProtoAddr (line 1387) | func netAddrToProtoAddr(addr netip.Addr) *Addr {
function netAddrToProtoV4AddrPort (line 1395) | func netAddrToProtoV4AddrPort(addr netip.Addr, port uint16) *V4AddrPort {
function netAddrToProtoV6AddrPort (line 1403) | func netAddrToProtoV6AddrPort(addr netip.Addr, port uint16) *V6AddrPort {
method GetRelays (line 1412) | func (d *NebulaMetaDetails) GetRelays() []netip.Addr {
function findNetworkUnion (line 1431) | func findNetworkUnion(prefixes []netip.Prefix, addrs []netip.Addr) (neti...
method GetVpnAddrAndVersion (line 1442) | func (d *NebulaMetaDetails) GetVpnAddrAndVersion() (netip.Addr, cert.Ver...
FILE: lighthouse_test.go
function TestOldIPv4Only (line 19) | func TestOldIPv4Only(t *testing.T) {
function Test_lhStaticMapping (line 30) | func Test_lhStaticMapping(t *testing.T) {
function TestReloadLighthouseInterval (line 55) | func TestReloadLighthouseInterval(t *testing.T) {
function BenchmarkLighthouseHandleRequest (line 90) | func BenchmarkLighthouseHandleRequest(b *testing.B) {
function TestLighthouse_Memory (line 169) | func TestLighthouse_Memory(t *testing.T) {
function TestLighthouse_reload (line 276) | func TestLighthouse_reload(t *testing.T) {
function newLHHostRequest (line 306) | func newLHHostRequest(fromAddr netip.AddrPort, myVpnIp, queryVpnIp netip...
function newLHHostUpdate (line 332) | func newLHHostUpdate(fromAddr netip.AddrPort, vpnIp netip.Addr, addrs []...
type testLhReply (line 362) | type testLhReply struct
type testEncWriter (line 369) | type testEncWriter struct
method SendVia (line 375) | func (tw *testEncWriter) SendVia(via *HostInfo, relay *Relay, ad, nb, ...
method Handshake (line 377) | func (tw *testEncWriter) Handshake(vpnIp netip.Addr) {
method SendMessageToHostInfo (line 380) | func (tw *testEncWriter) SendMessageToHostInfo(t header.MessageType, s...
method SendMessageToVpnAddr (line 397) | func (tw *testEncWriter) SendMessageToVpnAddr(t header.MessageType, st...
method GetHostInfo (line 414) | func (tw *testEncWriter) GetHostInfo(vpnIp netip.Addr) *HostInfo {
method GetCertState (line 418) | func (tw *testEncWriter) GetCertState() *CertState {
function assertIp4InArray (line 423) | func assertIp4InArray(t *testing.T, have []*V4AddrPort, want ...netip.Ad...
function Test_findNetworkUnion (line 436) | func Test_findNetworkUnion(t *testing.T) {
function TestLighthouse_Dont_Delete_Static_Hosts (line 496) | func TestLighthouse_Dont_Delete_Static_Hosts(t *testing.T) {
function TestLighthouse_DeletesWork (line 566) | func TestLighthouse_DeletesWork(t *testing.T) {
FILE: logger.go
function configLogger (line 12) | func configLogger(l *logrus.Logger, c *config.C) error {
FILE: main.go
function Main (line 23) | func Main(c *config.C, configTest bool, buildVersion string, logger *log...
function moduleVersion (line 303) | func moduleVersion() string {
FILE: message_metrics.go
type MessageMetrics (line 10) | type MessageMetrics struct
method Rx (line 18) | func (m *MessageMetrics) Rx(t header.MessageType, s header.MessageSubT...
method Tx (line 27) | func (m *MessageMetrics) Tx(t header.MessageType, s header.MessageSubT...
function newMessageMetrics (line 37) | func newMessageMetrics() *MessageMetrics {
function newMessageMetricsOnlyRecvError (line 63) | func newMessageMetricsOnlyRecvError() *MessageMetrics {
function newLighthouseMetrics (line 77) | func newLighthouseMetrics() *MessageMetrics {
FILE: nebula.pb.go
constant _ (line 23) | _ = proto.GoGoProtoPackageIsVersion3
type NebulaMeta_MessageType (line 25) | type NebulaMeta_MessageType
method String (line 69) | func (x NebulaMeta_MessageType) String() string {
method EnumDescriptor (line 73) | func (NebulaMeta_MessageType) EnumDescriptor() ([]byte, []int) {
constant NebulaMeta_None (line 28) | NebulaMeta_None NebulaMeta_MessageType = 0
constant NebulaMeta_HostQuery (line 29) | NebulaMeta_HostQuery NebulaMeta_MessageType = 1
constant NebulaMeta_HostQueryReply (line 30) | NebulaMeta_HostQueryReply NebulaMeta_MessageType = 2
constant NebulaMeta_HostUpdateNotification (line 31) | NebulaMeta_HostUpdateNotification NebulaMeta_MessageType = 3
constant NebulaMeta_HostMovedNotification (line 32) | NebulaMeta_HostMovedNotification NebulaMeta_MessageType = 4
constant NebulaMeta_HostPunchNotification (line 33) | NebulaMeta_HostPunchNotification NebulaMeta_MessageType = 5
constant NebulaMeta_HostWhoami (line 34) | NebulaMeta_HostWhoami NebulaMeta_MessageType = 6
constant NebulaMeta_HostWhoamiReply (line 35) | NebulaMeta_HostWhoamiReply NebulaMeta_MessageType = 7
constant NebulaMeta_PathCheck (line 36) | NebulaMeta_PathCheck NebulaMeta_MessageType = 8
constant NebulaMeta_PathCheckReply (line 37) | NebulaMeta_PathCheckReply NebulaMeta_MessageType = 9
constant NebulaMeta_HostUpdateNotificationAck (line 38) | NebulaMeta_HostUpdateNotificationAck NebulaMeta_MessageType = 10
type NebulaPing_MessageType (line 77) | type NebulaPing_MessageType
method String (line 94) | func (x NebulaPing_MessageType) String() string {
method EnumDescriptor (line 98) | func (NebulaPing_MessageType) EnumDescriptor() ([]byte, []int) {
constant NebulaPing_Ping (line 80) | NebulaPing_Ping NebulaPing_MessageType = 0
constant NebulaPing_Reply (line 81) | NebulaPing_Reply NebulaPing_MessageType = 1
type NebulaControl_MessageType (line 102) | type NebulaControl_MessageType
method String (line 122) | func (x NebulaControl_MessageType) String() string {
method EnumDescriptor (line 126) | func (NebulaControl_MessageType) EnumDescriptor() ([]byte, []int) {
constant NebulaControl_None (line 105) | NebulaControl_None NebulaControl_MessageType = 0
constant NebulaControl_CreateRelayRequest (line 106) | NebulaControl_CreateRelayRequest NebulaControl_MessageType = 1
constant NebulaControl_CreateRelayResponse (line 107) | NebulaControl_CreateRelayResponse NebulaControl_MessageType = 2
type NebulaMeta (line 130) | type NebulaMeta struct
method Reset (line 135) | func (m *NebulaMeta) Reset() { *m = NebulaMeta{} }
method String (line 136) | func (m *NebulaMeta) String() string { return proto.CompactTextString(...
method ProtoMessage (line 137) | func (*NebulaMeta) ProtoMessage() {}
method Descriptor (line 138) | func (*NebulaMeta) Descriptor() ([]byte, []int) {
method XXX_Unmarshal (line 141) | func (m *NebulaMeta) XXX_Unmarshal(b []byte) error {
method XXX_Marshal (line 144) | func (m *NebulaMeta) XXX_Marshal(b []byte, deterministic bool) ([]byte...
method XXX_Merge (line 156) | func (m *NebulaMeta) XXX_Merge(src proto.Message) {
method XXX_Size (line 159) | func (m *NebulaMeta) XXX_Size() int {
method XXX_DiscardUnknown (line 162) | func (m *NebulaMeta) XXX_DiscardUnknown() {
method GetType (line 168) | func (m *NebulaMeta) GetType() NebulaMeta_MessageType {
method GetDetails (line 175) | func (m *NebulaMeta) GetDetails() *NebulaMetaDetails {
method Marshal (line 793) | func (m *NebulaMeta) Marshal() (dAtA []byte, err error) {
method MarshalTo (line 803) | func (m *NebulaMeta) MarshalTo(dAtA []byte) (int, error) {
method MarshalToSizedBuffer (line 808) | func (m *NebulaMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) {
method Size (line 1255) | func (m *NebulaMeta) Size() (n int) {
method Unmarshal (line 1461) | func (m *NebulaMeta) Unmarshal(dAtA []byte) error {
type NebulaMetaDetails (line 182) | type NebulaMetaDetails struct
method Reset (line 192) | func (m *NebulaMetaDetails) Reset() { *m = NebulaMetaDetails{} }
method String (line 193) | func (m *NebulaMetaDetails) String() string { return proto.CompactText...
method ProtoMessage (line 194) | func (*NebulaMetaDetails) ProtoMessage() {}
method Descriptor (line 195) | func (*NebulaMetaDetails) Descriptor() ([]byte, []int) {
method XXX_Unmarshal (line 198) | func (m *NebulaMetaDetails) XXX_Unmarshal(b []byte) error {
method XXX_Marshal (line 201) | func (m *NebulaMetaDetails) XXX_Marshal(b []byte, deterministic bool) ...
method XXX_Merge (line 213) | func (m *NebulaMetaDetails) XXX_Merge(src proto.Message) {
method XXX_Size (line 216) | func (m *NebulaMetaDetails) XXX_Size() int {
method XXX_DiscardUnknown (line 219) | func (m *NebulaMetaDetails) XXX_DiscardUnknown() {
method GetOldVpnAddr (line 226) | func (m *NebulaMetaDetails) GetOldVpnAddr() uint32 {
method GetVpnAddr (line 233) | func (m *NebulaMetaDetails) GetVpnAddr() *Addr {
method GetOldRelayVpnAddrs (line 241) | func (m *NebulaMetaDetails) GetOldRelayVpnAddrs() []uint32 {
method GetRelayVpnAddrs (line 248) | func (m *NebulaMetaDetails) GetRelayVpnAddrs() []*Addr {
method GetV4AddrPorts (line 255) | func (m *NebulaMetaDetails) GetV4AddrPorts() []*V4AddrPort {
method GetV6AddrPorts (line 262) | func (m *NebulaMetaDetails) GetV6AddrPorts() []*V6AddrPort {
method GetCounter (line 269) | func (m *NebulaMetaDetails) GetCounter() uint32 {
method Marshal (line 833) | func (m *NebulaMetaDetails) Marshal() (dAtA []byte, err error) {
method MarshalTo (line 843) | func (m *NebulaMetaDetails) MarshalTo(dAtA []byte) (int, error) {
method MarshalToSizedBuffer (line 848) | func (m *NebulaMetaDetails) MarshalToSizedBuffer(dAtA []byte) (int, er...
method Size (line 1271) | func (m *NebulaMetaDetails) Size() (n int) {
method Unmarshal (line 1566) | func (m *NebulaMetaDetails) Unmarshal(dAtA []byte) error {
type Addr (line 276) | type Addr struct
method Reset (line 281) | func (m *Addr) Reset() { *m = Addr{} }
method String (line 282) | func (m *Addr) String() string { return proto.CompactTextString(m) }
method ProtoMessage (line 283) | func (*Addr) ProtoMessage() {}
method Descriptor (line 284) | func (*Addr) Descriptor() ([]byte, []int) {
method XXX_Unmarshal (line 287) | func (m *Addr) XXX_Unmarshal(b []byte) error {
method XXX_Marshal (line 290) | func (m *Addr) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro...
method XXX_Merge (line 302) | func (m *Addr) XXX_Merge(src proto.Message) {
method XXX_Size (line 305) | func (m *Addr) XXX_Size() int {
method XXX_DiscardUnknown (line 308) | func (m *Addr) XXX_DiscardUnknown() {
method GetHi (line 314) | func (m *Addr) GetHi() uint64 {
method GetLo (line 321) | func (m *Addr) GetLo() uint64 {
method Marshal (line 938) | func (m *Addr) Marshal() (dAtA []byte, err error) {
method MarshalTo (line 948) | func (m *Addr) MarshalTo(dAtA []byte) (int, error) {
method MarshalToSizedBuffer (line 953) | func (m *Addr) MarshalToSizedBuffer(dAtA []byte) (int, error) {
method Size (line 1315) | func (m *Addr) Size() (n int) {
method Unmarshal (line 1868) | func (m *Addr) Unmarshal(dAtA []byte) error {
type V4AddrPort (line 328) | type V4AddrPort struct
method Reset (line 333) | func (m *V4AddrPort) Reset() { *m = V4AddrPort{} }
method String (line 334) | func (m *V4AddrPort) String() string { return proto.CompactTextString(...
method ProtoMessage (line 335) | func (*V4AddrPort) ProtoMessage() {}
method Descriptor (line 336) | func (*V4AddrPort) Descriptor() ([]byte, []int) {
method XXX_Unmarshal (line 339) | func (m *V4AddrPort) XXX_Unmarshal(b []byte) error {
method XXX_Marshal (line 342) | func (m *V4AddrPort) XXX_Marshal(b []byte, deterministic bool) ([]byte...
method XXX_Merge (line 354) | func (m *V4AddrPort) XXX_Merge(src proto.Message) {
method XXX_Size (line 357) | func (m *V4AddrPort) XXX_Size() int {
method XXX_DiscardUnknown (line 360) | func (m *V4AddrPort) XXX_DiscardUnknown() {
method GetAddr (line 366) | func (m *V4AddrPort) GetAddr() uint32 {
method GetPort (line 373) | func (m *V4AddrPort) GetPort() uint32 {
method Marshal (line 971) | func (m *V4AddrPort) Marshal() (dAtA []byte, err error) {
method MarshalTo (line 981) | func (m *V4AddrPort) MarshalTo(dAtA []byte) (int, error) {
method MarshalToSizedBuffer (line 986) | func (m *V4AddrPort) MarshalToSizedBuffer(dAtA []byte) (int, error) {
method Size (line 1330) | func (m *V4AddrPort) Size() (n int) {
method Unmarshal (line 1956) | func (m *V4AddrPort) Unmarshal(dAtA []byte) error {
type V6AddrPort (line 380) | type V6AddrPort struct
method Reset (line 386) | func (m *V6AddrPort) Reset() { *m = V6AddrPort{} }
method String (line 387) | func (m *V6AddrPort) String() string { return proto.CompactTextString(...
method ProtoMessage (line 388) | func (*V6AddrPort) ProtoMessage() {}
method Descriptor (line 389) | func (*V6AddrPort) Descriptor() ([]byte, []int) {
method XXX_Unmarshal (line 392) | func (m *V6AddrPort) XXX_Unmarshal(b []byte) error {
method XXX_Marshal (line 395) | func (m *V6AddrPort) XXX_Marshal(b []byte, deterministic bool) ([]byte...
method XXX_Merge (line 407) | func (m *V6AddrPort) XXX_Merge(src proto.Message) {
method XXX_Size (line 410) | func (m *V6AddrPort) XXX_Size() int {
method XXX_DiscardUnknown (line 413) | func (m *V6AddrPort) XXX_DiscardUnknown() {
method GetHi (line 419) | func (m *V6AddrPort) GetHi() uint64 {
method GetLo (line 426) | func (m *V6AddrPort) GetLo() uint64 {
method GetPort (line 433) | func (m *V6AddrPort) GetPort() uint32 {
method Marshal (line 1004) | func (m *V6AddrPort) Marshal() (dAtA []byte, err error) {
method MarshalTo (line 1014) | func (m *V6AddrPort) MarshalTo(dAtA []byte) (int, error) {
method MarshalToSizedBuffer (line 1019) | func (m *V6AddrPort) MarshalToSizedBuffer(dAtA []byte) (int, error) {
method Size (line 1345) | func (m *V6AddrPort) Size() (n int) {
method Unmarshal (line 2044) | func (m *V6AddrPort) Unmarshal(dAtA []byte) error {
type NebulaPing (line 440) | type NebulaPing struct
method Reset (line 445) | func (m *NebulaPing) Reset() { *m = NebulaPing{} }
method String (line 446) | func (m *NebulaPing) String() string { return proto.CompactTextString(...
method ProtoMessage (line 447) | func (*NebulaPing) ProtoMessage() {}
method Descriptor (line 448) | func (*NebulaPing) Descriptor() ([]byte, []int) {
method XXX_Unmarshal (line 451) | func (m *NebulaPing) XXX_Unmarshal(b []byte) error {
method XXX_Marshal (line 454) | func (m *NebulaPing) XXX_Marshal(b []byte, deterministic bool) ([]byte...
method XXX_Merge (line 466) | func (m *NebulaPing) XXX_Merge(src proto.Message) {
method XXX_Size (line 469) | func (m *NebulaPing) XXX_Size() int {
method XXX_DiscardUnknown (line 472) | func (m *NebulaPing) XXX_DiscardUnknown() {
method GetType (line 478) | func (m *NebulaPing) GetType() NebulaPing_MessageType {
method GetTime (line 485) | func (m *NebulaPing) GetTime() uint64 {
method Marshal (line 1042) | func (m *NebulaPing) Marshal() (dAtA []byte, err error) {
method MarshalTo (line 1052) | func (m *NebulaPing) MarshalTo(dAtA []byte) (int, error) {
method MarshalToSizedBuffer (line 1057) | func (m *NebulaPing) MarshalToSizedBuffer(dAtA []byte) (int, error) {
method Size (line 1363) | func (m *NebulaPing) Size() (n int) {
method Unmarshal (line 2151) | func (m *NebulaPing) Unmarshal(dAtA []byte) error {
type NebulaHandshake (line 492) | type NebulaHandshake struct
method Reset (line 497) | func (m *NebulaHandshake) Reset() { *m = NebulaHandshake{} }
method String (line 498) | func (m *NebulaHandshake) String() string { return proto.CompactTextSt...
method ProtoMessage (line 499) | func (*NebulaHandshake) ProtoMessage() {}
method Descriptor (line 500) | func (*NebulaHandshake) Descriptor() ([]byte, []int) {
method XXX_Unmarshal (line 503) | func (m *NebulaHandshake) XXX_Unmarshal(b []byte) error {
method XXX_Marshal (line 506) | func (m *NebulaHandshake) XXX_Marshal(b []byte, deterministic bool) ([...
method XXX_Merge (line 518) | func (m *NebulaHandshake) XXX_Merge(src proto.Message) {
method XXX_Size (line 521) | func (m *NebulaHandshake) XXX_Size() int {
method XXX_DiscardUnknown (line 524) | func (m *NebulaHandshake) XXX_DiscardUnknown() {
method GetDetails (line 530) | func (m *NebulaHandshake) GetDetails() *NebulaHandshakeDetails {
method GetHmac (line 537) | func (m *NebulaHandshake) GetHmac() []byte {
method Marshal (line 1075) | func (m *NebulaHandshake) Marshal() (dAtA []byte, err error) {
method MarshalTo (line 1085) | func (m *NebulaHandshake) MarshalTo(dAtA []byte) (int, error) {
method MarshalToSizedBuffer (line 1090) | func (m *NebulaHandshake) MarshalToSizedBuffer(dAtA []byte) (int, erro...
method Size (line 1378) | func (m *NebulaHandshake) Size() (n int) {
method Unmarshal (line 2239) | func (m *NebulaHandshake) Unmarshal(dAtA []byte) error {
type NebulaHandshakeDetails (line 544) | type NebulaHandshakeDetails struct
method Reset (line 553) | func (m *NebulaHandshakeDetails) Reset() { *m = NebulaHandshak...
method String (line 554) | func (m *NebulaHandshakeDetails) String() string { return proto.Compac...
method ProtoMessage (line 555) | func (*NebulaHandshakeDetails) ProtoMessage() {}
method Descriptor (line 556) | func (*NebulaHandshakeDetails) Descriptor() ([]byte, []int) {
method XXX_Unmarshal (line 559) | func (m *NebulaHandshakeDetails) XXX_Unmarshal(b []byte) error {
method XXX_Marshal (line 562) | func (m *NebulaHandshakeDetails) XXX_Marshal(b []byte, deterministic b...
method XXX_Merge (line 574) | func (m *NebulaHandshakeDetails) XXX_Merge(src proto.Message) {
method XXX_Size (line 577) | func (m *NebulaHandshakeDetails) XXX_Size() int {
method XXX_DiscardUnknown (line 580) | func (m *NebulaHandshakeDetails) XXX_DiscardUnknown() {
method GetCert (line 586) | func (m *NebulaHandshakeDetails) GetCert() []byte {
method GetInitiatorIndex (line 593) | func (m *NebulaHandshakeDetails) GetInitiatorIndex() uint32 {
method GetResponderIndex (line 600) | func (m *NebulaHandshakeDetails) GetResponderIndex() uint32 {
method GetCookie (line 607) | func (m *NebulaHandshakeDetails) GetCookie() uint64 {
method GetTime (line 614) | func (m *NebulaHandshakeDetails) GetTime() uint64 {
method GetCertVersion (line 621) | func (m *NebulaHandshakeDetails) GetCertVersion() uint32 {
method Marshal (line 1117) | func (m *NebulaHandshakeDetails) Marshal() (dAtA []byte, err error) {
method MarshalTo (line 1127) | func (m *NebulaHandshakeDetails) MarshalTo(dAtA []byte) (int, error) {
method MarshalToSizedBuffer (line 1132) | func (m *NebulaHandshakeDetails) MarshalToSizedBuffer(dAtA []byte) (in...
method Size (line 1395) | func (m *NebulaHandshakeDetails) Size() (n int) {
method Unmarshal (line 2359) | func (m *NebulaHandshakeDetails) Unmarshal(dAtA []byte) error {
type NebulaControl (line 628) | type NebulaControl struct
method Reset (line 638) | func (m *NebulaControl) Reset() { *m = NebulaControl{} }
method String (line 639) | func (m *NebulaControl) String() string { return proto.CompactTextStri...
method ProtoMessage (line 640) | func (*NebulaControl) ProtoMessage() {}
method Descriptor (line 641) | func (*NebulaControl) Descriptor() ([]byte, []int) {
method XXX_Unmarshal (line 644) | func (m *NebulaControl) XXX_Unmarshal(b []byte) error {
method XXX_Marshal (line 647) | func (m *NebulaControl) XXX_Marshal(b []byte, deterministic bool) ([]b...
method XXX_Merge (line 659) | func (m *NebulaControl) XXX_Merge(src proto.Message) {
method XXX_Size (line 662) | func (m *NebulaControl) XXX_Size() int {
method XXX_DiscardUnknown (line 665) | func (m *NebulaControl) XXX_DiscardUnknown() {
method GetType (line 671) | func (m *NebulaControl) GetType() NebulaControl_MessageType {
method GetInitiatorRelayIndex (line 678) | func (m *NebulaControl) GetInitiatorRelayIndex() uint32 {
method GetResponderRelayIndex (line 685) | func (m *NebulaControl) GetResponderRelayIndex() uint32 {
method GetOldRelayToAddr (line 693) | func (m *NebulaControl) GetOldRelayToAddr() uint32 {
method GetOldRelayFromAddr (line 701) | func (m *NebulaControl) GetOldRelayFromAddr() uint32 {
method GetRelayToAddr (line 708) | func (m *NebulaControl) GetRelayToAddr() *Addr {
method GetRelayFromAddr (line 715) | func (m *NebulaControl) GetRelayFromAddr() *Addr {
method Marshal (line 1172) | func (m *NebulaControl) Marshal() (dAtA []byte, err error) {
method MarshalTo (line 1182) | func (m *NebulaControl) MarshalTo(dAtA []byte) (int, error) {
method MarshalToSizedBuffer (line 1187) | func (m *NebulaControl) MarshalToSizedBuffer(dAtA []byte) (int, error) {
method Size (line 1423) | func (m *NebulaControl) Size() (n int) {
method Unmarshal (line 2538) | func (m *NebulaControl) Unmarshal(dAtA []byte) error {
function init (line 722) | func init() {
function init (line 737) | func init() { proto.RegisterFile("nebula.proto", fileDescriptor_2d65afa7...
function encodeVarintNebula (line 1244) | func encodeVarintNebula(dAtA []byte, offset int, v uint64) int {
function sovNebula (line 1455) | func sovNebula(x uint64) (n int) {
function sozNebula (line 1458) | func sozNebula(x uint64) (n int) {
function skipNebula (line 2755) | func skipNebula(dAtA []byte) (n int, err error) {
FILE: noise.go
type endianness (line 11) | type endianness interface
type NebulaCipherState (line 17) | type NebulaCipherState struct
method EncryptDanger (line 36) | func (s *NebulaCipherState) EncryptDanger(out, ad, plaintext []byte, n...
method DecryptDanger (line 57) | func (s *NebulaCipherState) DecryptDanger(out, ad, ciphertext []byte, ...
method Overhead (line 70) | func (s *NebulaCipherState) Overhead() int {
function NewNebulaCipherState (line 23) | func NewNebulaCipherState(s *noise.CipherState) *NebulaCipherState {
FILE: noiseutil/boring.go
constant EncryptLockNeeded (line 20) | EncryptLockNeeded = true
function newGCMTLS (line 37) | func newGCMTLS(c cipher.Block) (cipher.AEAD, error)
type cipherFn (line 39) | type cipherFn struct
method Cipher (line 44) | func (c cipherFn) Cipher(k [32]byte) noise.Cipher { return c.fn(k) }
method CipherName (line 45) | func (c cipherFn) CipherName() string { return c.name }
function cipherAESGCMBoring (line 50) | func cipherAESGCMBoring(k [32]byte) noise.Cipher {
type aeadCipher (line 69) | type aeadCipher struct
method Encrypt (line 74) | func (c aeadCipher) Encrypt(out []byte, n uint64, ad, plaintext []byte...
method Decrypt (line 78) | func (c aeadCipher) Decrypt(out []byte, n uint64, ad, ciphertext []byt...
FILE: noiseutil/boring_test.go
function TestEncryptLockNeeded (line 14) | func TestEncryptLockNeeded(t *testing.T) {
function TestNewGCMTLS (line 19) | func TestNewGCMTLS(t *testing.T) {
FILE: noiseutil/nist.go
type nistCurve (line 15) | type nistCurve struct
method GenerateKeypair (line 32) | func (c nistCurve) GenerateKeypair(rng io.Reader) (noise.DHKey, error) {
method DH (line 44) | func (c nistCurve) DH(privkey, pubkey []byte) ([]byte, error) {
method DHLen (line 57) | func (c nistCurve) DHLen() int {
method DHName (line 68) | func (c nistCurve) DHName() string { return c.name }
function newNISTCurve (line 22) | func newNISTCurve(name string, curve ecdh.Curve, byteLen int) nistCurve {
FILE: noiseutil/notboring.go
constant EncryptLockNeeded (line 11) | EncryptLockNeeded = false
FILE: noiseutil/notboring_test.go
function TestEncryptLockNeeded (line 12) | func TestEncryptLockNeeded(t *testing.T) {
FILE: noiseutil/pkcs11.go
type nistP11Curve (line 16) | type nistP11Curve struct
method DH (line 26) | func (c nistP11Curve) DH(privkey, pubkey []byte) ([]byte, error) {
function newNISTP11Curve (line 20) | func newNISTP11Curve(name string, curve ecdh.Curve, byteLen int) nistP11...
FILE: outside.go
constant minFwPacketLen (line 19) | minFwPacketLen = 4
method readOutsidePackets (line 22) | func (f *Interface) readOutsidePackets(via ViaSender, out []byte, packet...
method closeTunnel (line 227) | func (f *Interface) closeTunnel(hostInfo *HostInfo) {
method sendCloseTunnel (line 236) | func (f *Interface) sendCloseTunnel(h *HostInfo) {
method handleHostRoaming (line 240) | func (f *Interface) handleHostRoaming(hostinfo *HostInfo, via ViaSender) {
method handleEncrypted (line 265) | func (f *Interface) handleEncrypted(ci *ConnectionState, via ViaSender, ...
function newPacket (line 291) | func newPacket(data []byte, incoming bool, fp *firewall.Packet) error {
function parseV6 (line 306) | func parseV6(data []byte, incoming bool, fp *firewall.Packet) error {
function parseV4 (line 419) | func parseV4(data []byte, incoming bool, fp *firewall.Packet) error {
method decrypt (line 479) | func (f *Interface) decrypt(hostinfo *HostInfo, mc uint64, out []byte, p...
method decryptToTun (line 495) | func (f *Interface) decryptToTun(hostinfo *HostInfo, messageCounter uint...
method maybeSendRecvError (line 538) | func (f *Interface) maybeSendRecvError(endpoint netip.AddrPort, index ui...
method sendRecvError (line 544) | func (f *Interface) sendRecvError(endpoint netip.AddrPort, index uint32) {
method handleRecvError (line 556) | func (f *Interface) handleRecvError(addr netip.AddrPort, h *header.H) {
FILE: outside_test.go
function Test_newPacket (line 19) | func Test_newPacket(t *testing.T) {
function Test_newPacket_v6 (line 98) | func Test_newPacket_v6(t *testing.T) {
function Test_newPacket_ipv6Fragment (line 347) | func Test_newPacket_ipv6Fragment(t *testing.T) {
function BenchmarkParseV6 (line 454) | func BenchmarkParseV6(b *testing.B) {
function padAuthData (line 601) | func padAuthData(authData []byte) []byte {
function serializeAH (line 611) | func serializeAH(ah *layers.IPSecAH) []byte {
FILE: overlay/device.go
type Device (line 10) | type Device interface
FILE: overlay/route.go
type Route (line 17) | type Route struct
method Equal (line 27) | func (r Route) Equal(t Route) bool {
method String (line 43) | func (r Route) String() string {
function makeRouteTree (line 51) | func makeRouteTree(l *logrus.Logger, routes []Route, allowMTU bool) (*ba...
function parseRoutes (line 67) | func parseRoutes(c *config.C, networks []netip.Prefix) ([]Route, error) {
function parseUnsafeRoutes (line 146) | func parseUnsafeRoutes(c *config.C, networks []netip.Prefix) ([]Route, e...
function ipWithin (line 309) | func ipWithin(o *net.IPNet, i *net.IPNet) bool {
FILE: overlay/route_test.go
function Test_parseRoutes (line 15) | func Test_parseRoutes(t *testing.T) {
function Test_parseUnsafeRoutes (line 120) | func Test_parseUnsafeRoutes(t *testing.T) {
function Test_makeRouteTree (line 285) | func Test_makeRouteTree(t *testing.T) {
function Test_makeMultipathUnsafeRouteTree (line 325) | func Test_makeMultipathUnsafeRouteTree(t *testing.T) {
FILE: overlay/tun.go
constant DefaultMTU (line 13) | DefaultMTU = 1300
type NameError (line 15) | type NameError struct
method Error (line 20) | func (e *NameError) Error() string {
type DeviceFactory (line 25) | type DeviceFactory
function NewDeviceFromConfig (line 27) | func NewDeviceFromConfig(c *config.C, l *logrus.Logger, vpnNetworks []ne...
function NewFdDeviceFromConfig (line 38) | func NewFdDeviceFromConfig(fd *int) DeviceFactory {
function getAllRoutesFromConfig (line 44) | func getAllRoutesFromConfig(c *config.C, vpnNetworks []netip.Prefix, ini...
function findRemovedRoutes (line 65) | func findRemovedRoutes(newRoutes, oldRoutes []Route) []Route {
function prefixToMask (line 85) | func prefixToMask(prefix netip.Prefix) netip.Addr {
function flipBytes (line 95) | func flipBytes(b []byte) []byte {
function orBytes (line 101) | func orBytes(a []byte, b []byte) []byte {
function getBroadcast (line 109) | func getBroadcast(cidr netip.Prefix) netip.Addr {
function selectGateway (line 119) | func selectGateway(dest netip.Prefix, gateways []netip.Prefix) (netip.Pr...
FILE: overlay/tun_android.go
type tun (line 20) | type tun struct
method RoutesFor (line 60) | func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
method Activate (line 65) | func (t tun) Activate() error {
method reload (line 69) | func (t *tun) reload(c *config.C, initial bool) error {
method Networks (line 90) | func (t *tun) Networks() []netip.Prefix {
method Name (line 94) | func (t *tun) Name() string {
method SupportsMultiqueue (line 98) | func (t *tun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 102) | func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
function newTunFromFd (line 29) | func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetwor...
function newTun (line 56) | func newTun(_ *config.C, _ *logrus.Logger, _ []netip.Prefix, _ bool) (*t...
FILE: overlay/tun_darwin.go
type tun (line 25) | type tun struct
method deviceBytes (line 149) | func (t *tun) deviceBytes() (o [16]byte) {
method Close (line 160) | func (t *tun) Close() error {
method Activate (line 167) | func (t *tun) Activate() error {
method activate4 (line 227) | func (t *tun) activate4(network netip.Prefix) error {
method activate6 (line 269) | func (t *tun) activate6(network netip.Prefix) error {
method reload (line 307) | func (t *tun) reload(c *config.C, initial bool) error {
method RoutesFor (line 344) | func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
method addRoutes (line 380) | func (t *tun) addRoutes(logErrors bool) error {
method removeRoutes (line 410) | func (t *tun) removeRoutes(routes []Route) error {
method Read (line 506) | func (t *tun) Read(to []byte) (int, error) {
method Write (line 516) | func (t *tun) Write(from []byte) (int, error) {
method Networks (line 544) | func (t *tun) Networks() []netip.Prefix {
method Name (line 548) | func (t *tun) Name() string {
method SupportsMultiqueue (line 552) | func (t *tun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 556) | func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
type ifReq (line 39) | type ifReq struct
constant _SIOCAIFADDR_IN6 (line 46) | _SIOCAIFADDR_IN6 = 2155899162
constant _UTUN_OPT_IFNAME (line 47) | _UTUN_OPT_IFNAME = 2
constant _IN6_IFF_NODAD (line 48) | _IN6_IFF_NODAD = 0x0020
constant _IN6_IFF_SECURED (line 49) | _IN6_IFF_SECURED = 0x0400
constant utunControlName (line 50) | utunControlName = "com.apple.net.utun_control"
type ifreqMTU (line 53) | type ifreqMTU struct
type addrLifetime (line 59) | type addrLifetime struct
type ifreqAlias4 (line 66) | type ifreqAlias4 struct
type ifreqAlias6 (line 73) | type ifreqAlias6 struct
function newTun (line 82) | func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, _...
function newTunFromFd (line 156) | func newTunFromFd(_ *config.C, _ *logrus.Logger, _ int, _ []netip.Prefix...
function getLinkAddr (line 355) | func getLinkAddr(name string) (*netroute.LinkAddr, error) {
function addRoute (line 426) | func addRoute(prefix netip.Prefix, gateway netroute.Addr) error {
function delRoute (line 467) | func delRoute(prefix netip.Prefix, gateway netroute.Addr) error {
FILE: overlay/tun_disabled.go
type disabledTun (line 15) | type disabledTun struct
method Activate (line 43) | func (*disabledTun) Activate() error {
method RoutesFor (line 47) | func (*disabledTun) RoutesFor(addr netip.Addr) routing.Gateways {
method Networks (line 51) | func (t *disabledTun) Networks() []netip.Prefix {
method Name (line 55) | func (*disabledTun) Name() string {
method Read (line 59) | func (t *disabledTun) Read(b []byte) (int, error) {
method handleICMPEchoRequest (line 77) | func (t *disabledTun) handleICMPEchoRequest(b []byte) bool {
method Write (line 94) | func (t *disabledTun) Write(b []byte) (int, error) {
method SupportsMultiqueue (line 108) | func (t *disabledTun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 112) | func (t *disabledTun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
method Close (line 116) | func (t *disabledTun) Close() error {
function newDisabledTun (line 25) | func newDisabledTun(vpnNetworks []netip.Prefix, queueLen int, metricsEna...
type prettyPacket (line 124) | type prettyPacket
method String (line 126) | func (p prettyPacket) String() string {
FILE: overlay/tun_freebsd.go
constant FIODGNAME (line 30) | FIODGNAME = 0x80106678
constant TUNSIFMODE (line 31) | TUNSIFMODE = 0x8004745e
constant TUNSIFHEAD (line 32) | TUNSIFHEAD = 0x80047460
constant OSIOCAIFADDR_IN6 (line 33) | OSIOCAIFADDR_IN6 = 0x8088691b
constant IN6_IFF_NODAD (line 34) | IN6_IFF_NODAD = 0x0020
type fiodgnameArg (line 37) | type fiodgnameArg struct
type ifreqRename (line 43) | type ifreqRename struct
type ifreqDestroy (line 48) | type ifreqDestroy struct
type ifReq (line 53) | type ifReq struct
type ifreqMTU (line 58) | type ifreqMTU struct
type addrLifetime (line 63) | type addrLifetime struct
type ifreqAlias4 (line 70) | type ifreqAlias4 struct
type ifreqAlias6 (line 78) | type ifreqAlias6 struct
type tun (line 88) | type tun struct
method Read (line 99) | func (t *tun) Read(to []byte) (int, error) {
method Write (line 133) | func (t *tun) Write(from []byte) (int, error) {
method Close (line 169) | func (t *tun) Close() error {
method addIp (line 295) | func (t *tun) addIp(cidr netip.Prefix) error {
method Activate (line 364) | func (t *tun) Activate() error {
method setMTU (line 390) | func (t *tun) setMTU() error {
method reload (line 403) | func (t *tun) reload(c *config.C, initial bool) error {
method RoutesFor (line 440) | func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
method Networks (line 445) | func (t *tun) Networks() []netip.Prefix {
method Name (line 449) | func (t *tun) Name() string {
method SupportsMultiqueue (line 453) | func (t *tun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 457) | func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
method addRoutes (line 461) | func (t *tun) addRoutes(logErrors bool) error {
method removeRoutes (line 485) | func (t *tun) removeRoutes(routes []Route) error {
method deviceBytes (line 501) | func (t *tun) deviceBytes() (o [16]byte) {
function newTunFromFd (line 202) | func newTunFromFd(_ *config.C, _ *logrus.Logger, _ int, _ []netip.Prefix...
function newTun (line 206) | func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, _...
function addRoute (line 508) | func addRoute(prefix netip.Prefix, gateway netroute.Addr) error {
function delRoute (line 560) | func delRoute(prefix netip.Prefix, gateway netroute.Addr) error {
function getLinkAddr (line 600) | func getLinkAddr(name string) (*netroute.LinkAddr, error) {
FILE: overlay/tun_ios.go
type tun (line 23) | type tun struct
method Activate (line 58) | func (t *tun) Activate() error {
method reload (line 62) | func (t *tun) reload(c *config.C, initial bool) error {
method RoutesFor (line 83) | func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
method Networks (line 146) | func (t *tun) Networks() []netip.Prefix {
method Name (line 150) | func (t *tun) Name() string {
method SupportsMultiqueue (line 154) | func (t *tun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 158) | func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
function newTun (line 31) | func newTun(_ *config.C, _ *logrus.Logger, _ []netip.Prefix, _ bool) (*t...
function newTunFromFd (line 35) | func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetwor...
type tunReadCloser (line 89) | type tunReadCloser struct
method Read (line 99) | func (tr *tunReadCloser) Read(to []byte) (int, error) {
method Write (line 113) | func (tr *tunReadCloser) Write(from []byte) (int, error) {
method Close (line 142) | func (tr *tunReadCloser) Close() error {
FILE: overlay/tun_linux.go
type tun (line 27) | type tun struct
method Networks (line 52) | func (t *tun) Networks() []netip.Prefix {
method reload (line 163) | func (t *tun) reload(c *config.C, initial bool) error {
method SupportsMultiqueue (line 237) | func (t *tun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 241) | func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
method RoutesFor (line 259) | func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
method Write (line 264) | func (t *tun) Write(b []byte) (int, error) {
method deviceBytes (line 287) | func (t *tun) deviceBytes() (o [16]byte) {
method addIPs (line 304) | func (t *tun) addIPs(link netlink.Link) error {
method Activate (line 345) | func (t *tun) Activate() error {
method setMTU (line 421) | func (t *tun) setMTU() {
method setDefaultRoute (line 430) | func (t *tun) setDefaultRoute(cidr netip.Prefix) error {
method addRoutes (line 468) | func (t *tun) addRoutes(logErrors bool) error {
method removeRoutes (line 509) | func (t *tun) removeRoutes(routes []Route) {
method Name (line 541) | func (t *tun) Name() string {
method advMSS (line 545) | func (t *tun) advMSS(r Route) int {
method watchRoutes (line 558) | func (t *tun) watchRoutes() {
method isGatewayInVpnNetworks (line 594) | func (t *tun) isGatewayInVpnNetworks(gwAddr netip.Addr) bool {
method getGatewaysFromRoute (line 606) | func (t *tun) getGatewaysFromRoute(r *netlink.Route) routing.Gateways {
method updateRoutes (line 670) | func (t *tun) updateRoutes(r netlink.RouteUpdate) {
method Close (line 709) | func (t *tun) Close() error {
type ifReq (line 56) | type ifReq struct
type ifreqMTU (line 62) | type ifreqMTU struct
type ifreqQLEN (line 68) | type ifreqQLEN struct
function newTunFromFd (line 74) | func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetwor...
function newTun (line 87) | func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, m...
function newTunGeneric (line 136) | func newTunGeneric(c *config.C, l *logrus.Logger, file *os.File, vpnNetw...
function hasNetlinkAddr (line 294) | func hasNetlinkAddr(al []*netlink.Addr, x netlink.Addr) bool {
function getGatewayAddr (line 651) | func getGatewayAddr(gw net.IP, via netlink.Destination) (netip.Addr, boo...
FILE: overlay/tun_linux_test.go
function TestTunAdvMSS (line 25) | func TestTunAdvMSS(t *testing.T) {
FILE: overlay/tun_netbsd.go
constant SIOCAIFADDR_IN6 (line 27) | SIOCAIFADDR_IN6 = 0x8080696b
constant TUNSIFHEAD (line 28) | TUNSIFHEAD = 0x80047442
constant TUNSIFMODE (line 29) | TUNSIFMODE = 0x80047458
type ifreqAlias4 (line 32) | type ifreqAlias4 struct
type ifreqAlias6 (line 39) | type ifreqAlias6 struct
type ifreq (line 48) | type ifreq struct
type addrLifetime (line 53) | type addrLifetime struct
type tun (line 60) | type tun struct
method Close (line 122) | func (t *tun) Close() error {
method Read (line 144) | func (t *tun) Read(to []byte) (int, error) {
method Write (line 192) | func (t *tun) Write(from []byte) (int, error) {
method addIp (line 237) | func (t *tun) addIp(cidr netip.Prefix) error {
method Activate (line 303) | func (t *tun) Activate() error {
method doIoctlByName (line 331) | func (t *tun) doIoctlByName(ctl uintptr, value uint32) error {
method reload (line 343) | func (t *tun) reload(c *config.C, initial bool) error {
method RoutesFor (line 380) | func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
method Networks (line 385) | func (t *tun) Networks() []netip.Prefix {
method Name (line 389) | func (t *tun) Name() string {
method SupportsMultiqueue (line 393) | func (t *tun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 397) | func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
method addRoutes (line 401) | func (t *tun) addRoutes(logErrors bool) error {
method removeRoutes (line 426) | func (t *tun) removeRoutes(routes []Route) error {
method deviceBytes (line 442) | func (t *tun) deviceBytes() (o [16]byte) {
function newTunFromFd (line 73) | func newTunFromFd(_ *config.C, _ *logrus.Logger, _ int, _ []netip.Prefix...
function newTun (line 77) | func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, _...
function addRoute (line 449) | func addRoute(prefix netip.Prefix, gateways []netip.Prefix) error {
function delRoute (line 508) | func delRoute(prefix netip.Prefix, gateways []netip.Prefix) error {
FILE: overlay/tun_notwin.go
function ioctl (line 8) | func ioctl(a1, a2, a3 uintptr) error {
FILE: overlay/tun_openbsd.go
constant SIOCAIFADDR_IN6 (line 27) | SIOCAIFADDR_IN6 = 0x8080691a
type ifreqAlias4 (line 30) | type ifreqAlias4 struct
type ifreqAlias6 (line 37) | type ifreqAlias6 struct
type ifreq (line 46) | type ifreq struct
type tun (line 51) | type tun struct
method Close (line 115) | func (t *tun) Close() error {
method Read (line 127) | func (t *tun) Read(to []byte) (int, error) {
method Write (line 137) | func (t *tun) Write(from []byte) (int, error) {
method addIp (line 165) | func (t *tun) addIp(cidr netip.Prefix) error {
method Activate (line 235) | func (t *tun) Activate() error {
method doIoctlByName (line 251) | func (t *tun) doIoctlByName(ctl uintptr, value uint32) error {
method reload (line 263) | func (t *tun) reload(c *config.C, initial bool) error {
method RoutesFor (line 300) | func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
method Networks (line 305) | func (t *tun) Networks() []netip.Prefix {
method Name (line 309) | func (t *tun) Name() string {
method SupportsMultiqueue (line 313) | func (t *tun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 317) | func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
method addRoutes (line 321) | func (t *tun) addRoutes(logErrors bool) error {
method removeRoutes (line 346) | func (t *tun) removeRoutes(routes []Route) error {
method deviceBytes (line 362) | func (t *tun) deviceBytes() (o [16]byte) {
function newTunFromFd (line 66) | func newTunFromFd(_ *config.C, _ *logrus.Logger, _ int, _ []netip.Prefix...
function newTun (line 70) | func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, _...
function addRoute (line 369) | func addRoute(prefix netip.Prefix, gateways []netip.Prefix) error {
function delRoute (line 428) | func delRoute(prefix netip.Prefix, gateways []netip.Prefix) error {
FILE: overlay/tun_tester.go
type TestTun (line 19) | type TestTun struct
method Send (line 59) | func (t *TestTun) Send(packet []byte) {
method Get (line 73) | func (t *TestTun) Get(block bool) []byte {
method RoutesFor (line 90) | func (t *TestTun) RoutesFor(ip netip.Addr) routing.Gateways {
method Activate (line 95) | func (t *TestTun) Activate() error {
method Networks (line 99) | func (t *TestTun) Networks() []netip.Prefix {
method Name (line 103) | func (t *TestTun) Name() string {
method Write (line 107) | func (t *TestTun) Write(b []byte) (n int, err error) {
method Close (line 118) | func (t *TestTun) Close() error {
method Read (line 126) | func (t *TestTun) Read(b []byte) (int, error) {
method SupportsMultiqueue (line 135) | func (t *TestTun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 139) | func (t *TestTun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
function newTun (line 31) | func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, _...
function newTunFromFd (line 52) | func newTunFromFd(_ *config.C, _ *logrus.Logger, _ int, _ []netip.Prefix...
FILE: overlay/tun_windows.go
constant tunGUIDLabel (line 28) | tunGUIDLabel = "Fixed Nebula Windows GUID v1"
type winTun (line 30) | type winTun struct
method reload (line 95) | func (t *winTun) reload(c *config.C, initial bool) error {
method Activate (line 132) | func (t *winTun) Activate() error {
method addRoutes (line 148) | func (t *winTun) addRoutes(logErrors bool) error {
method removeRoutes (line 200) | func (t *winTun) removeRoutes(routes []Route) error {
method RoutesFor (line 219) | func (t *winTun) RoutesFor(ip netip.Addr) routing.Gateways {
method Networks (line 224) | func (t *winTun) Networks() []netip.Prefix {
method Name (line 228) | func (t *winTun) Name() string {
method Read (line 232) | func (t *winTun) Read(b []byte) (int, error) {
method Write (line 236) | func (t *winTun) Write(b []byte) (int, error) {
method SupportsMultiqueue (line 240) | func (t *winTun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 244) | func (t *winTun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
method Close (line 248) | func (t *winTun) Close() error {
function newTunFromFd (line 41) | func newTunFromFd(_ *config.C, _ *logrus.Logger, _ int, _ []netip.Prefix...
function newTun (line 45) | func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, _...
function generateGUIDByDeviceName (line 264) | func generateGUIDByDeviceName(name string) (*windows.GUID, error) {
function checkWinTunExists (line 283) | func checkWinTunExists() error {
FILE: overlay/user.go
function NewUserDeviceFromConfig (line 12) | func NewUserDeviceFromConfig(c *config.C, l *logrus.Logger, vpnNetworks ...
function NewUserDevice (line 16) | func NewUserDevice(vpnNetworks []netip.Prefix) (Device, error) {
type UserDevice (line 29) | type UserDevice struct
method Activate (line 39) | func (d *UserDevice) Activate() error {
method Networks (line 43) | func (d *UserDevice) Networks() []netip.Prefix { return d.vpnNetworks }
method Name (line 44) | func (d *UserDevice) Name() string { return "faketun0" }
method RoutesFor (line 45) | func (d *UserDevice) RoutesFor(ip netip.Addr) routing.Gateways {
method SupportsMultiqueue (line 49) | func (d *UserDevice) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 53) | func (d *UserDevice) NewMultiQueueReader() (io.ReadWriteCloser, error) {
method Pipe (line 57) | func (d *UserDevice) Pipe() (*io.PipeReader, *io.PipeWriter) {
method Read (line 61) | func (d *UserDevice) Read(p []byte) (n int, err error) {
method Write (line 64) | func (d *UserDevice) Write(p []byte) (n int, err error) {
method Close (line 67) | func (d *UserDevice) Close() error {
FILE: pkclient/pkclient.go
type Client (line 13) | type Client interface
constant NoiseKeySize (line 20) | NoiseKeySize = 32
function FromUrl (line 22) | func FromUrl(pkurl string) (*PKClient, error) {
function ecKeyToArray (line 53) | func ecKeyToArray(key *ecdsa.PublicKey) []byte {
function formatPubkeyFromPublicKeyInfoAttr (line 61) | func formatPubkeyFromPublicKeyInfoAttr(d []byte) ([]byte, error) {
method Test (line 74) | func (c *PKClient) Test() error {
FILE: pkclient/pkclient_cgo.go
type PKClient (line 16) | type PKClient struct
method Close (line 85) | func (c *PKClient) Close() error {
method findDeriveKey (line 98) | func (c *PKClient) findDeriveKey(id []byte, label []byte, private bool...
method listDeriveKeys (line 118) | func (c *PKClient) listDeriveKeys(id []byte, label []byte, private boo...
method SignASN1 (line 148) | func (c *PKClient) SignASN1(data []byte) ([]byte, error) {
method DeriveNoise (line 169) | func (c *PKClient) DeriveNoise(peerPubKey []byte) ([]byte, error) {
method GetPubKey (line 203) | func (c *PKClient) GetPubKey() ([]byte, error) {
type ecdsaSignature (line 25) | type ecdsaSignature struct
function New (line 30) | func New(hsmPath string, slotId uint, pin string, id string, label strin...
FILE: pkclient/pkclient_stub.go
type PKClient (line 7) | type PKClient struct
method Close (line 16) | func (c *PKClient) Close() error {
method SignASN1 (line 20) | func (c *PKClient) SignASN1(data []byte) ([]byte, error) {
method DeriveNoise (line 24) | func (c *PKClient) DeriveNoise(_ []byte) ([]byte, error) {
method GetPubKey (line 28) | func (c *PKClient) GetPubKey() ([]byte, error) {
function New (line 12) | func New(hsmPath string, slotId uint, pin string, id string, label strin...
FILE: pki.go
type PKI (line 23) | type PKI struct
method GetCAPool (line 65) | func (p *PKI) GetCAPool() *cert.CAPool {
method getCertState (line 69) | func (p *PKI) getCertState() *CertState {
method reload (line 73) | func (p *PKI) reload(c *config.C, initial bool) error {
method reloadCerts (line 93) | func (p *PKI) reloadCerts(c *config.C, initial bool) *util.ContextualE...
method reloadCAPool (line 191) | func (p *PKI) reloadCAPool(c *config.C) *util.ContextualError {
type CertState (line 29) | type CertState struct
method GetDefaultCertificate (line 202) | func (cs *CertState) GetDefaultCertificate() cert.Certificate {
method getCertificate (line 210) | func (cs *CertState) getCertificate(v cert.Version) cert.Certificate {
method getHandshakeBytes (line 223) | func (cs *CertState) getHandshakeBytes(v cert.Version) []byte {
method String (line 234) | func (cs *CertState) String() string {
method MarshalJSON (line 242) | func (cs *CertState) MarshalJSON() ([]byte, error) {
function NewPKIFromConfig (line 48) | func NewPKIFromConfig(l *logrus.Logger, c *config.C) (*PKI, error) {
function newCertStateFromConfig (line 263) | func newCertStateFromConfig(c *config.C) (*CertState, error) {
function newCertState (line 350) | func newCertState(dv cert.Version, v1, v2 cert.Certificate, pkcs11backed...
function loadPrivateKey (line 442) | func loadPrivateKey(privPathOrPEM string) (rawKey []byte, curve cert.Cur...
function loadCertificate (line 468) | func loadCertificate(b []byte) (cert.Certificate, []byte, error) {
function loadCAPoolFromConfig (line 489) | func loadCAPoolFromConfig(l *logrus.Logger, c *config.C) (*cert.CAPool, ...
FILE: punchy.go
type Punchy (line 11) | type Punchy struct
method reload (line 31) | func (p *Punchy) reload(c *config.C, initial bool) {
method GetPunch (line 92) | func (p *Punchy) GetPunch() bool {
method GetRespond (line 96) | func (p *Punchy) GetRespond() bool {
method GetDelay (line 100) | func (p *Punchy) GetDelay() time.Duration {
method GetRespondDelay (line 104) | func (p *Punchy) GetRespondDelay() time.Duration {
method GetTargetEverything (line 108) | func (p *Punchy) GetTargetEverything() bool {
function NewPunchyFromConfig (line 20) | func NewPunchyFromConfig(l *logrus.Logger, c *config.C) *Punchy {
FILE: punchy_test.go
function TestNewPunchyFromConfig (line 13) | func TestNewPunchyFromConfig(t *testing.T) {
function TestPunchy_reload (line 56) | func TestPunchy_reload(t *testing.T) {
FILE: relay_manager.go
type relayManager (line 17) | type relayManager struct
method reload (line 38) | func (rm *relayManager) reload(c *config.C, initial bool) error {
method GetAmRelay (line 45) | func (rm *relayManager) GetAmRelay() bool {
method setAmRelay (line 49) | func (rm *relayManager) setAmRelay(v bool) {
method EstablishRelay (line 92) | func (rm *relayManager) EstablishRelay(relayHostInfo *HostInfo, m *Neb...
method HandleControlMsg (line 119) | func (rm *relayManager) HandleControlMsg(h *HostInfo, d []byte, f *Int...
method handleCreateRelayResponse (line 149) | func (rm *relayManager) handleCreateRelayResponse(v cert.Version, h *H...
method handleCreateRelayRequest (line 231) | func (rm *relayManager) handleCreateRelayRequest(v cert.Version, h *Ho...
function NewRelayManager (line 23) | func NewRelayManager(ctx context.Context, l *logrus.Logger, hostmap *Hos...
function AddRelay (line 55) | func AddRelay(l *logrus.Logger, relayHostInfo *HostInfo, hm *HostMap, vp...
FILE: remote_list.go
type forEachFunc (line 18) | type forEachFunc
type checkFuncV4 (line 21) | type checkFuncV4
type checkFuncV6 (line 22) | type checkFuncV6
type CacheMap (line 26) | type CacheMap
type Cache (line 30) | type Cache struct
type cache (line 37) | type cache struct
type cacheRelay (line 43) | type cacheRelay struct
type cacheV4 (line 48) | type cacheV4 struct
type cacheV6 (line 54) | type cacheV6 struct
type hostnamePort (line 59) | type hostnamePort struct
type hostnamesResults (line 64) | type hostnamesResults struct
method Cancel (line 165) | func (hr *hostnamesResults) Cancel() {
method GetAddrs (line 171) | func (hr *hostnamesResults) GetAddrs() []netip.AddrPort {
function NewHostnameResults (line 73) | func NewHostnameResults(ctx context.Context, l *logrus.Logger, d time.Du...
type RemoteList (line 186) | type RemoteList struct
method unlockedSetHostnamesResults (line 230) | func (r *RemoteList) unlockedSetHostnamesResults(hr *hostnamesResults) {
method Len (line 238) | func (r *RemoteList) Len(preferredRanges []netip.Prefix) int {
method ForEach (line 247) | func (r *RemoteList) ForEach(preferredRanges []netip.Prefix, forEach f...
method CopyAddrs (line 258) | func (r *RemoteList) CopyAddrs(preferredRanges []netip.Prefix) []netip...
method LearnRemote (line 277) | func (r *RemoteList) LearnRemote(ownerVpnIp netip.Addr, remote netip.A...
method CopyCache (line 289) | func (r *RemoteList) CopyCache() *CacheMap {
method BlockRemote (line 341) | func (r *RemoteList) BlockRemote(bad ViaSender) {
method CopyBlockedRemotes (line 362) | func (r *RemoteList) CopyBlockedRemotes() []netip.AddrPort {
method RefreshFromHandshake (line 374) | func (r *RemoteList) RefreshFromHandshake(vpnAddrs []netip.Addr) {
method ResetBlockedRemotes (line 383) | func (r *RemoteList) ResetBlockedRemotes() {
method Rebuild (line 391) | func (r *RemoteList) Rebuild(preferredRanges []netip.Prefix) {
method unlockedIsBad (line 406) | func (r *RemoteList) unlockedIsBad(remote netip.AddrPort) bool {
method unlockedSetLearnedV4 (line 412) | func (r *RemoteList) unlockedSetLearnedV4(ownerVpnIp netip.Addr, to *V...
method unlockedSetV4 (line 419) | func (r *RemoteList) unlockedSetV4(ownerVpnIp, vpnIp netip.Addr, to []...
method unlockedSetRelay (line 434) | func (r *RemoteList) unlockedSetRelay(ownerVpnIp netip.Addr, to []neti...
method unlockedPrependV4 (line 447) | func (r *RemoteList) unlockedPrependV4(ownerVpnIp netip.Addr, to *V4Ad...
method unlockedSetLearnedV6 (line 460) | func (r *RemoteList) unlockedSetLearnedV6(ownerVpnIp netip.Addr, to *V...
method unlockedSetV6 (line 467) | func (r *RemoteList) unlockedSetV6(ownerVpnIp, vpnIp netip.Addr, to []...
method unlockedPrependV6 (line 484) | func (r *RemoteList) unlockedPrependV6(ownerVpnIp netip.Addr, to *V6Ad...
method unlockedGetOrMakeRelay (line 495) | func (r *RemoteList) unlockedGetOrMakeRelay(ownerVpnIp netip.Addr) *ca...
method unlockedGetOrMakeV4 (line 510) | func (r *RemoteList) unlockedGetOrMakeV4(ownerVpnIp netip.Addr) *cache...
method unlockedGetOrMakeV6 (line 525) | func (r *RemoteList) unlockedGetOrMakeV6(ownerVpnIp netip.Addr) *cache...
method unlockedCollect (line 540) | func (r *RemoteList) unlockedCollect() {
method unlockedSort (line 599) | func (r *RemoteList) unlockedSort(preferredRanges []netip.Prefix) {
function NewRemoteList (line 218) | func NewRemoteList(vpnAddrs []netip.Addr, shouldAdd func([]netip.Addr, n...
function minInt (line 704) | func minInt(a, b int) int {
function isPreferred (line 712) | func isPreferred(ip netip.Addr, preferredRanges []netip.Prefix) bool {
FILE: remote_list_test.go
function TestRemoteList_Rebuild (line 11) | func TestRemoteList_Rebuild(t *testing.T) {
function BenchmarkFullRebuild (line 115) | func BenchmarkFullRebuild(b *testing.B) {
function BenchmarkSortRebuild (line 177) | func BenchmarkSortRebuild(b *testing.B) {
function newIp4AndPortFromString (line 242) | func newIp4AndPortFromString(s string) *V4AddrPort {
function newIp6AndPortFromString (line 251) | func newIp6AndPortFromString(s string) *V6AddrPort {
FILE: routing/balance.go
function hashPacket (line 14) | func hashPacket(p *firewall.Packet) int {
function BalancePacket (line 27) | func BalancePacket(fwPacket *firewall.Packet, gateways []Gateway) (netip...
FILE: routing/balance_test.go
function TestPacketsAreBalancedEqually (line 11) | func TestPacketsAreBalancedEqually(t *testing.T) {
function TestPacketsAreBalancedByPriority (line 61) | func TestPacketsAreBalancedByPriority(t *testing.T) {
function TestBalancePacketDistributsRandomlyAndReturnsFalseIfBucketsNotCalculated (line 105) | func TestBalancePacketDistributsRandomlyAndReturnsFalseIfBucketsNotCalcu...
FILE: routing/gateway.go
constant BucketNotCalculated (line 10) | BucketNotCalculated = -1
type Gateways (line 13) | type Gateways
method String (line 15) | func (g Gateways) String() string {
type Gateway (line 26) | type Gateway struct
method BucketUpperBound (line 36) | func (g *Gateway) BucketUpperBound() int {
method Addr (line 40) | func (g *Gateway) Addr() netip.Addr {
method String (line 44) | func (g *Gateway) String() string {
function NewGateway (line 32) | func NewGateway(addr netip.Addr, weight int) Gateway {
function divideAndRound (line 49) | func divideAndRound(v uint64, d uint64) uint64 {
function CalculateBucketsForGateways (line 57) | func CalculateBucketsForGateways(gateways []Gateway) {
FILE: routing/gateway_test.go
function TestRebalance3_2Split (line 10) | func TestRebalance3_2Split(t *testing.T) {
function TestRebalanceEqualSplit (line 22) | func TestRebalanceEqualSplit(t *testing.T) {
FILE: service/listener.go
type tcpListener (line 8) | type tcpListener struct
method Accept (line 15) | func (l *tcpListener) Accept() (net.Conn, error) {
method Close (line 23) | func (l *tcpListener) Close() error {
method Addr (line 34) | func (l *tcpListener) Addr() net.Addr {
FILE: service/service.go
constant nicID (line 32) | nicID = 1
type Service (line 34) | type Service struct
method DialContext (line 155) | func (s *Service) DialContext(ctx context.Context, network, address st...
method Dial (line 187) | func (s *Service) Dial(network, address string) (net.Conn, error) {
method Listen (line 193) | func (s *Service) Listen(network, address string) (net.Listener, error) {
method Wait (line 230) | func (s *Service) Wait() error {
method Close (line 234) | func (s *Service) Close() error {
method tcpHandler (line 239) | func (s *Service) tcpHandler(r *tcp.ForwarderRequest) {
function New (line 46) | func New(control *nebula.Control) (*Service, error) {
function getProtocolNumber (line 147) | func getProtocolNumber(addr netip.Addr) tcpip.NetworkProtocolNumber {
FILE: service/service_test.go
function newSimpleService (line 25) | func newSimpleService(caCrt cert.Certificate, caKey []byte, name string,...
function TestService (line 93) | func TestService(t *testing.T) {
FILE: ssh.go
type sshListHostMapFlags (line 26) | type sshListHostMapFlags struct
type sshPrintCertFlags (line 32) | type sshPrintCertFlags struct
type sshPrintTunnelFlags (line 38) | type sshPrintTunnelFlags struct
type sshChangeRemoteFlags (line 42) | type sshChangeRemoteFlags struct
type sshCloseTunnelFlags (line 46) | type sshCloseTunnelFlags struct
type sshCreateTunnelFlags (line 50) | type sshCreateTunnelFlags struct
type sshDeviceInfoFlags (line 54) | type sshDeviceInfoFlags struct
function wireSSHReload (line 59) | func wireSSHReload(l *logrus.Logger, ssh *sshd.SSHServer, c *config.C) {
function configSSH (line 80) | func configSSH(l *logrus.Logger, ssh *sshd.SSHServer, c *config.C) (func...
function attachCommands (line 190) | func attachCommands(l *logrus.Logger, c *config.C, ssh *sshd.SSHServer, ...
function sshListHostMap (line 415) | func sshListHostMap(hl controlHostLister, a any, w sshd.StringWriter) er...
function sshListLighthouseMap (line 455) | func sshListLighthouseMap(lightHouse *LightHouse, a any, w sshd.StringWr...
function sshStartCpuProfile (line 509) | func sshStartCpuProfile(fs any, a []string, w sshd.StringWriter) error {
function sshVersion (line 531) | func sshVersion(ifce *Interface, fs any, a []string, w sshd.StringWriter...
function sshQueryLighthouse (line 535) | func sshQueryLighthouse(ifce *Interface, fs any, a []string, w sshd.Stri...
function sshCloseTunnel (line 557) | func sshCloseTunnel(ifce *Interface, fs any, a []string, w sshd.StringWr...
function sshCreateTunnel (line 597) | func sshCreateTunnel(ifce *Interface, fs any, a []string, w sshd.StringW...
function sshChangeRemote (line 642) | func sshChangeRemote(ifce *Interface, fs any, a []string, w sshd.StringW...
function sshGetHeapProfile (line 679) | func sshGetHeapProfile(fs any, a []string, w sshd.StringWriter) error {
function sshMutexProfileFraction (line 700) | func sshMutexProfileFraction(fs any, a []string, w sshd.StringWriter) er...
function sshGetMutexProfile (line 715) | func sshGetMutexProfile(fs any, a []string, w sshd.StringWriter) error {
function sshLogLevel (line 739) | func sshLogLevel(l *logrus.Logger, fs any, a []string, w sshd.StringWrit...
function sshLogFormat (line 753) | func sshLogFormat(l *logrus.Logger, fs any, a []string, w sshd.StringWri...
function sshPrintCert (line 771) | func sshPrintCert(ifce *Interface, fs any, a []string, w sshd.StringWrit...
function sshPrintRelays (line 826) | func sshPrintRelays(ifce *Interface, fs any, a []string, w sshd.StringWr...
function sshPrintTunnel (line 921) | func sshPrintTunnel(ifce *Interface, fs any, a []string, w sshd.StringWr...
function sshDeviceInfo (line 953) | func sshDeviceInfo(ifce *Interface, fs any, w sshd.StringWriter) error {
function sshReload (line 982) | func sshReload(c *config.C, w sshd.StringWriter) error {
FILE: sshd/command.go
type CommandFlags (line 15) | type CommandFlags
type CommandCallback (line 24) | type CommandCallback
type Command (line 26) | type Command struct
function execCommand (line 34) | func execCommand(c *Command, args []string, w StringWriter) error {
function dumpCommands (line 57) | func dumpCommands(c *radix.Tree, w StringWriter) {
function lookupCommand (line 72) | func lookupCommand(c *radix.Tree, sCmd string) (*Command, error) {
function matchCommand (line 86) | func matchCommand(c *radix.Tree, cmd string) []string {
function allCommands (line 96) | func allCommands(c *radix.Tree) []*Command {
function helpCallback (line 108) | func helpCallback(commands *radix.Tree, a []string, w StringWriter) (err...
function checkHelpArgs (line 153) | func checkHelpArgs(args []string) bool {
FILE: sshd/server.go
type SSHServer (line 15) | type SSHServer struct
method SetHostKey (line 97) | func (s *SSHServer) SetHostKey(hostPrivateKey []byte) error {
method ClearTrustedCAs (line 107) | func (s *SSHServer) ClearTrustedCAs() {
method ClearAuthorizedKeys (line 111) | func (s *SSHServer) ClearAuthorizedKeys() {
method AddTrustedCA (line 116) | func (s *SSHServer) AddTrustedCA(pubKey string) error {
method AddAuthorizedKey (line 128) | func (s *SSHServer) AddAuthorizedKey(user, pubKey string) error {
method RegisterCommand (line 146) | func (s *SSHServer) RegisterCommand(c *Command) {
method Run (line 151) | func (s *SSHServer) Run(addr string) error {
method run (line 169) | func (s *SSHServer) run() {
method Stop (line 219) | func (s *SSHServer) Stop() {
method closeSessions (line 228) | func (s *SSHServer) closeSessions() {
function NewSSHServer (line 37) | func NewSSHServer(l *logrus.Entry) (*SSHServer, error) {
FILE: sshd/session.go
type session (line 15) | type session struct
method handleChannels (line 44) | func (s *session) handleChannels(chans <-chan ssh.NewChannel) {
method handleRequests (line 62) | func (s *session) handleRequests(in <-chan *ssh.Request, channel ssh.C...
method createTerm (line 109) | func (s *session) createTerm(channel ssh.Channel) *term.Terminal {
method handleInput (line 130) | func (s *session) handleInput(channel ssh.Channel) {
method dispatchCommand (line 143) | func (s *session) dispatchCommand(line string, w StringWriter) {
method Close (line 176) | func (s *session) Close() {
function NewSession (line 23) | func NewSession(commands *radix.Tree, conn *ssh.ServerConn, chans <-chan...
FILE: sshd/writer.go
type StringWriter (line 5) | type StringWriter interface
type stringWriter (line 12) | type stringWriter struct
method WriteLine (line 16) | func (w *stringWriter) WriteLine(s string) error {
method Write (line 20) | func (w *stringWriter) Write(s string) error {
method WriteBytes (line 25) | func (w *stringWriter) WriteBytes(b []byte) error {
method GetWriter (line 30) | func (w *stringWriter) GetWriter() io.Writer {
FILE: stats.go
function startStats (line 25) | func startStats(l *logrus.Logger, c *config.C, buildVersion string, conf...
function startGraphiteStats (line 62) | func startGraphiteStats(l *logrus.Logger, i time.Duration, c *config.C, ...
function startPrometheusStats (line 82) | func startPrometheusStats(l *logrus.Logger, i time.Duration, c *config.C...
FILE: test/assert.go
function AssertDeepCopyEqual (line 16) | func AssertDeepCopyEqual(t *testing.T, a any, b any) {
function traverseDeepCopy (line 27) | func traverseDeepCopy(t *testing.T, v1 reflect.Value, v2 reflect.Value, ...
FILE: test/logger.go
function NewLogger (line 10) | func NewLogger() *logrus.Logger {
FILE: test/tun.go
type NoopTun (line 11) | type NoopTun struct
method RoutesFor (line 13) | func (NoopTun) RoutesFor(addr netip.Addr) routing.Gateways {
method Activate (line 17) | func (NoopTun) Activate() error {
method Networks (line 21) | func (NoopTun) Networks() []netip.Prefix {
method Name (line 25) | func (NoopTun) Name() string {
method Read (line 29) | func (NoopTun) Read([]byte) (int, error) {
method Write (line 33) | func (NoopTun) Write([]byte) (int, error) {
method SupportsMultiqueue (line 37) | func (NoopTun) SupportsMultiqueue() bool {
method NewMultiQueueReader (line 41) | func (NoopTun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
method Close (line 45) | func (NoopTun) Close() error {
FILE: timeout.go
constant timerCacheMax (line 9) | timerCacheMax = 50000
type TimerWheel (line 11) | type TimerWheel struct
type LockingTimerWheel (line 36) | type LockingTimerWheel struct
type TimeoutList (line 42) | type TimeoutList struct
type TimeoutItem (line 48) | type TimeoutItem struct
function NewTimerWheel (line 57) | func NewTimerWheel[T any](min, max time.Duration) *TimerWheel[T] {
function NewLockingTimerWheel (line 84) | func NewLockingTimerWheel[T any](min, max time.Duration) *LockingTimerWh...
method Add (line 92) | func (tw *TimerWheel[T]) Add(v T, timeout time.Duration) *TimeoutItem[T] {
method Purge (line 120) | func (tw *TimerWheel[T]) Purge() (T, bool) {
method findWheel (line 147) | func (tw *TimerWheel[T]) findWheel(timeout time.Duration) (i int) {
method Advance (line 171) | func (tw *TimerWheel[T]) Advance(now time.Time) {
method Add (line 209) | func (lw *LockingTimerWheel[T]) Add(v T, timeout time.Duration) *Timeout...
method Purge (line 215) | func (lw *LockingTimerWheel[T]) Purge() (T, bool) {
method Advance (line 221) | func (lw *LockingTimerWheel[T]) Advance(now time.Time) {
FILE: timeout_test.go
function TestNewTimerWheel (line 12) | func TestNewTimerWheel(t *testing.T) {
function TestTimerWheel_findWheel (line 42) | func TestTimerWheel_findWheel(t *testing.T) {
function TestTimerWheel_Add (line 64) | func TestTimerWheel_Add(t *testing.T) {
function TestTimerWheel_Purge (line 110) | func TestTimerWheel_Purge(t *testing.T) {
FILE: udp/conn.go
constant MTU (line 9) | MTU = 9001
type EncReader (line 11) | type EncReader
type Conn (line 16) | type Conn interface
type NoopConn (line 26) | type NoopConn struct
method Rebind (line 28) | func (NoopConn) Rebind() error {
method LocalAddr (line 31) | func (NoopConn) LocalAddr() (netip.AddrPort, error) {
method ListenOut (line 34) | func (NoopConn) ListenOut(_ EncReader) {
method SupportsMultipleReaders (line 37) | func (NoopConn) SupportsMultipleReaders() bool {
method WriteTo (line 40) | func (NoopConn) WriteTo(_ []byte, _ netip.AddrPort) error {
method ReloadConfig (line 43) | func (NoopConn) ReloadConfig(_ *config.C) {
method Close (line 46) | func (NoopConn) Close() error {
FILE: udp/udp_android.go
function NewListener (line 16) | func NewListener(l *logrus.Logger, ip netip.Addr, port int, multi bool, ...
function NewListenConfig (line 20) | func NewListenConfig(multi bool) net.ListenConfig {
method Rebind (line 43) | func (u *GenericConn) Rebind() error {
FILE: udp/udp_bsd.go
function NewListener (line 19) | func NewListener(l *logrus.Logger, ip netip.Addr, port int, multi bool, ...
function NewListenConfig (line 23) | func NewListenConfig(multi bool) net.ListenConfig {
method Rebind (line 46) | func (u *GenericConn) Rebind() error {
FILE: udp/udp_darwin.go
type StdConn (line 21) | type StdConn struct
method WriteTo (line 92) | func (u *StdConn) WriteTo(b []byte, ap netip.AddrPort) error {
method LocalAddr (line 143) | func (u *StdConn) LocalAddr() (netip.AddrPort, error) {
method ReloadConfig (line 159) | func (u *StdConn) ReloadConfig(c *config.C) {
method ListenOut (line 168) | func (u *StdConn) ListenOut(r EncReader) {
method SupportsMultipleReaders (line 187) | func (u *StdConn) SupportsMultipleReaders() bool {
method Rebind (line 191) | func (u *StdConn) Rebind() error {
function NewListener (line 30) | func NewListener(l *logrus.Logger, ip netip.Addr, port int, multi bool, ...
function NewListenConfig (line 64) | func NewListenConfig(multi bool) net.ListenConfig {
function sendto (line 90) | func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen int...
function NewUDPStatsEmitter (line 163) | func NewUDPStatsEmitter(udpConns []Conn) func() {
FILE: udp/udp_generic.go
type GenericConn (line 23) | type GenericConn struct
method WriteTo (line 42) | func (u *GenericConn) WriteTo(b []byte, addr netip.AddrPort) error {
method LocalAddr (line 47) | func (u *GenericConn) LocalAddr() (netip.AddrPort, error) {
method ReloadConfig (line 63) | func (u *GenericConn) ReloadConfig(c *config.C) {
method ListenOut (line 76) | func (u *GenericConn) ListenOut(r EncReader) {
method SupportsMultipleReaders (line 101) | func (u *GenericConn) SupportsMultipleReaders() bool {
function NewGenericListener (line 30) | func NewGenericListener(l *logrus.Logger, ip netip.Addr, port int, multi...
function NewUDPStatsEmitter (line 67) | func NewUDPStatsEmitter(udpConns []Conn) func() {
type rawMessage (line 72) | type rawMessage struct
FILE: udp/udp_linux.go
type StdConn (line 20) | type StdConn struct
method SupportsMultipleReaders (line 75) | func (u *StdConn) SupportsMultipleReaders() bool {
method Rebind (line 79) | func (u *StdConn) Rebind() error {
method SetRecvBuffer (line 83) | func (u *StdConn) SetRecvBuffer(n int) error {
method SetSendBuffer (line 87) | func (u *StdConn) SetSendBuffer(n int) error {
method SetSoMark (line 91) | func (u *StdConn) SetSoMark(mark int) error {
method GetRecvBuffer (line 95) | func (u *StdConn) GetRecvBuffer() (int, error) {
method GetSendBuffer (line 99) | func (u *StdConn) GetSendBuffer() (int, error) {
method GetSoMark (line 103) | func (u *StdConn) GetSoMark() (int, error) {
method LocalAddr (line 107) | func (u *StdConn) LocalAddr() (netip.AddrPort, error) {
method ListenOut (line 125) | func (u *StdConn) ListenOut(r EncReader) {
method ReadSingle (line 153) | func (u *StdConn) ReadSingle(msgs []rawMessage) (int, error) {
method ReadMulti (line 174) | func (u *StdConn) ReadMulti(msgs []rawMessage) (int, error) {
method WriteTo (line 194) | func (u *StdConn) WriteTo(b []byte, ip netip.AddrPort) error {
method writeTo6 (line 201) | func (u *StdConn) writeTo6(b []byte, ip netip.AddrPort) error {
method writeTo4 (line 226) | func (u *StdConn) writeTo4(b []byte, ip netip.AddrPort) error {
method ReloadConfig (line 255) | func (u *StdConn) ReloadConfig(c *config.C) {
method getMemInfo (line 303) | func (u *StdConn) getMemInfo(meminfo *[unix.SK_MEMINFO_VARS]uint32) er...
method Close (line 312) | func (u *StdConn) Close() error {
function maybeIPV4 (line 27) | func maybeIPV4(ip net.IP) (net.IP, bool) {
function NewListener (line 35) | func NewListener(l *logrus.Logger, ip netip.Addr, port int, multi bool, ...
function NewUDPStatsEmitter (line 316) | func NewUDPStatsEmitter(udpConns []Conn) func() {
FILE: udp/udp_linux_32.go
type iovec (line 13) | type iovec struct
type msghdr (line 18) | type msghdr struct
type rawMessage (line 28) | type rawMessage struct
method PrepareRawMessages (line 33) | func (u *StdConn) PrepareRawMessages(n int) ([]rawMessage, [][]byte, [][...
FILE: udp/udp_linux_64.go
type iovec (line 13) | type iovec struct
type msghdr (line 18) | type msghdr struct
type rawMessage (line 30) | type rawMessage struct
method PrepareRawMessages (line 36) | func (u *StdConn) PrepareRawMessages(n int) ([]rawMessage, [][]byte, [][...
FILE: udp/udp_netbsd.go
function NewListener (line 18) | func NewListener(l *logrus.Logger, ip netip.Addr, port int, multi bool, ...
function NewListenConfig (line 22) | func NewListenConfig(multi bool) net.ListenConfig {
method Rebind (line 45) | func (u *GenericConn) Rebind() error {
FILE: udp/udp_rio_windows.go
function procyield (line 30) | func procyield(cycles uint32)
constant packetsPerRing (line 33) | packetsPerRing = 1024
constant bytesPerPacket (line 34) | bytesPerPacket = 2048 - 32
constant receiveSpins (line 35) | receiveSpins = 15
type ringPacket (line 38) | type ringPacket struct
type ringBuffer (line 43) | type ringBuffer struct
method Push (line 357) | func (ring *ringBuffer) Push() *ringPacket {
method Return (line 369) | func (ring *ringBuffer) Return(count uint32) {
method CloseAndZero (line 377) | func (ring *ringBuffer) CloseAndZero() {
method Open (line 403) | func (ring *ringBuffer) Open() error {
type RIOConn (line 54) | type RIOConn struct
method bind (line 86) | func (u *RIOConn) bind(l *logrus.Logger, sa windows.Sockaddr) error {
method ListenOut (line 143) | func (u *RIOConn) ListenOut(r EncReader) {
method insertReceiveRequest (line 169) | func (u *RIOConn) insertReceiveRequest() error {
method receive (line 185) | func (u *RIOConn) receive(buf []byte) (int, windows.RawSockaddrInet6, ...
method WriteTo (line 257) | func (u *RIOConn) WriteTo(buf []byte, ip netip.AddrPort) error {
method LocalAddr (line 320) | func (u *RIOConn) LocalAddr() (netip.AddrPort, error) {
method SupportsMultipleReaders (line 331) | func (u *RIOConn) SupportsMultipleReaders() bool {
method Rebind (line 335) | func (u *RIOConn) Rebind() error {
method ReloadConfig (line 339) | func (u *RIOConn) ReloadConfig(*config.C) {}
method Close (line 341) | func (u *RIOConn) Close() error {
function NewRIOListener (line 63) | func NewRIOListener(l *logrus.Logger, addr netip.Addr, port int) (*RIOCo...
FILE: udp/udp_tester.go
type Packet (line 16) | type Packet struct
method Copy (line 22) | func (u *Packet) Copy() *Packet {
type TesterConn (line 33) | type TesterConn struct
method Send (line 55) | func (u *TesterConn) Send(packet *Packet) {
method Get (line 76) | func (u *TesterConn) Get(block bool) *Packet {
method WriteTo (line 93) | func (u *TesterConn) WriteTo(b []byte, addr netip.AddrPort) error {
method ListenOut (line 109) | func (u *TesterConn) ListenOut(r EncReader) {
method ReloadConfig (line 119) | func (u *TesterConn) ReloadConfig(*config.C) {}
method LocalAddr (line 126) | func (u *TesterConn) LocalAddr() (netip.AddrPort, error) {
method SupportsMultipleReaders (line 130) | func (u *TesterConn) SupportsMultipleReaders() bool {
method Rebind (line 134) | func (u *TesterConn) Rebind() error {
method Close (line 138) | func (u *TesterConn) Close() error {
function NewListener (line 43) | func NewListener(l *logrus.Logger, ip netip.Addr, port int, _ bool, _ in...
function NewUDPStatsEmitter (line 121) | func NewUDPStatsEmitter(_ []Conn) func() {
FILE: udp/udp_windows.go
function NewListener (line 15) | func NewListener(l *logrus.Logger, ip netip.Addr, port int, multi bool, ...
function NewListenConfig (line 32) | func NewListenConfig(multi bool) net.ListenConfig {
method Rebind (line 45) | func (u *GenericConn) Rebind() error {
FILE: util/error.go
type ContextualError (line 10) | type ContextualError struct
method Error (line 40) | func (ce *ContextualError) Error() string {
method Unwrap (line 47) | func (ce *ContextualError) Unwrap() error {
method Log (line 54) | func (ce *ContextualError) Log(lr *logrus.Logger) {
function NewContextualError (line 16) | func NewContextualError(msg string, fields map[string]any, realError err...
function ContextualizeIfNeeded (line 21) | func ContextualizeIfNeeded(msg string, err error) error {
function LogWithContextIfNeeded (line 31) | func LogWithContextIfNeeded(msg string, err error, l *logrus.Logger) {
FILE: util/error_test.go
type TestLogWriter (line 14) | type TestLogWriter struct
method Write (line 22) | func (tl *TestLogWriter) Write(p []byte) (n int, err error) {
method Reset (line 27) | func (tl *TestLogWriter) Reset() {
function NewTestLogWriter (line 18) | func NewTestLogWriter() *TestLogWriter {
function TestContextualError_Log (line 31) | func TestContextualError_Log(t *testing.T) {
function TestLogWithContextIfNeeded (line 72) | func TestLogWithContextIfNeeded(t *testing.T) {
function TestContextualizeIfNeeded (line 95) | func TestContextualizeIfNeeded(t *testing.T) {
FILE: wintun/device.go
type Device (line 17) | type Device interface
FILE: wintun/tun.go
constant rateMeasurementGranularity (line 29) | rateMeasurementGranularity = uint64((time.Second / 2) / time.Nanosecond)
constant spinloopRateThreshold (line 30) | spinloopRateThreshold = 800000000 / 8
constant spinloopDuration (line 31) | spinloopDuration = uint64(time.Millisecond / 80 / time.Nanosec...
type rateJuggler (line 34) | type rateJuggler struct
method update (line 196) | func (rate *rateJuggler) update(packetLen uint64) {
type NativeTun (line 41) | type NativeTun struct
method Name (line 91) | func (tun *NativeTun) Name() (string, error) {
method File (line 95) | func (tun *NativeTun) File() *os.File {
method Close (line 99) | func (tun *NativeTun) Close() error {
method Read (line 115) | func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
method Flush (line 152) | func (tun *NativeTun) Flush() error {
method Write (line 156) | func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
method LUID (line 182) | func (tun *NativeTun) LUID() uint64 {
method RunningVersion (line 192) | func (tun *NativeTun) RunningVersion() (version uint32, err error) {
function procyield (line 57) | func procyield(cycles uint32)
function nanotime (line 60) | func nanotime() int64
function CreateTUN (line 64) | func CreateTUN(ifname string, mtu int) (Device, error) {
function CreateTUNWithRequestedGUID (line 70) | func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GU...
Condensed preview — 216 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,502K chars).
[
{
"path": ".github/ISSUE_TEMPLATE/bug-report.yml",
"chars": 1874,
"preview": "name: \"\\U0001F41B Bug Report\"\ndescription: Report an issue or possible bug\ntitle: \"\\U0001F41B BUG:\"\nlabels: []\nassignees"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 1105,
"preview": "blank_issues_enabled: true\ncontact_links:\n - name: 💨 Performance Issues\n url: https://github.com/slackhq/nebula/disc"
},
{
"path": ".github/dependabot.yml",
"chars": 502,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"github-actions\"\n directory: \"/\"\n schedule:\n interval: \"weekly\"\n\n "
},
{
"path": ".github/pull_request_template.md",
"chars": 647,
"preview": "<!--\nThank you for taking the time to submit a pull request!\n\nPlease be sure to provide a clear description of what you'"
},
{
"path": ".github/workflows/gofmt.yml",
"chars": 674,
"preview": "name: gofmt\non:\n push:\n branches:\n - master\n pull_request:\n paths:\n - '.github/workflows/gofmt.yml'\n "
},
{
"path": ".github/workflows/release.yml",
"chars": 8262,
"preview": "on:\n push:\n tags:\n - 'v[0-9]+.[0-9]+.[0-9]*'\n\nname: Create release and upload binaries\n\njobs:\n build-linux:\n "
},
{
"path": ".github/workflows/smoke/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": ".github/workflows/smoke/Dockerfile",
"chars": 155,
"preview": "FROM ubuntu:jammy\n\nRUN apt-get update && apt-get install -y iputils-ping ncat tcpdump\n\nADD ./build /nebula\n\nWORKDIR /neb"
},
{
"path": ".github/workflows/smoke/build-relay.sh",
"chars": 1160,
"preview": "#!/bin/sh\n\nset -e -x\n\nrm -rf ./build\nmkdir ./build\n\n(\n cd build\n\n cp ../../../../build/linux-amd64/nebula .\n cp"
},
{
"path": ".github/workflows/smoke/build.sh",
"chars": 1629,
"preview": "#!/bin/sh\n\nset -e -x\n\nrm -rf ./build\nmkdir ./build\n\n# TODO: Assumes your docker bridge network is a /24, and the first c"
},
{
"path": ".github/workflows/smoke/genconfig.sh",
"chars": 1064,
"preview": "#!/bin/sh\n\nset -e\n\nFIREWALL_ALL='[{\"port\": \"any\", \"proto\": \"any\", \"host\": \"any\"}]'\n\nif [ \"$STATIC_HOSTS\" ] || [ \"$LIGHTH"
},
{
"path": ".github/workflows/smoke/smoke-relay.sh",
"chars": 2434,
"preview": "#!/bin/bash\n\nset -e -x\n\nset -o pipefail\n\nmkdir -p logs\n\ncleanup() {\n echo\n echo \" *** cleanup\"\n echo\n\n set +"
},
{
"path": ".github/workflows/smoke/smoke-vagrant.sh",
"chars": 3213,
"preview": "#!/bin/bash\n\nset -e -x\n\nset -o pipefail\n\nexport VAGRANT_CWD=\"$PWD/vagrant-$1\"\n\nmkdir -p logs\n\ncleanup() {\n echo\n e"
},
{
"path": ".github/workflows/smoke/smoke.sh",
"chars": 4687,
"preview": "#!/bin/bash\n\nset -e -x\n\nset -o pipefail\n\nmkdir -p logs\n\ncleanup() {\n echo\n echo \" *** cleanup\"\n echo\n\n set +"
},
{
"path": ".github/workflows/smoke/vagrant-freebsd-amd64/Vagrantfile",
"chars": 182,
"preview": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\nVagrant.configure(\"2\") do |config|\n config.vm.box = \"generic/freebsd14\"\n\n con"
},
{
"path": ".github/workflows/smoke/vagrant-linux-386/Vagrantfile",
"chars": 165,
"preview": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\nVagrant.configure(\"2\") do |config|\n config.vm.box = \"ubuntu/xenial32\"\n\n confi"
},
{
"path": ".github/workflows/smoke/vagrant-linux-amd64-ipv6disable/Vagrantfile",
"chars": 409,
"preview": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\nVagrant.configure(\"2\") do |config|\n config.vm.box = \"ubuntu/jammy64\"\n\n config"
},
{
"path": ".github/workflows/smoke/vagrant-netbsd-amd64/Vagrantfile",
"chars": 180,
"preview": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\nVagrant.configure(\"2\") do |config|\n config.vm.box = \"generic/netbsd9\"\n\n confi"
},
{
"path": ".github/workflows/smoke/vagrant-openbsd-amd64/Vagrantfile",
"chars": 181,
"preview": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\nVagrant.configure(\"2\") do |config|\n config.vm.box = \"generic/openbsd7\"\n\n conf"
},
{
"path": ".github/workflows/smoke-extra.yml",
"chars": 1567,
"preview": "name: smoke-extra\non:\n push:\n branches:\n - master\n pull_request:\n types: [opened, synchronize, labeled, reo"
},
{
"path": ".github/workflows/smoke.yml",
"chars": 1218,
"preview": "name: smoke\non:\n push:\n branches:\n - master\n pull_request:\n paths:\n - '.github/workflows/smoke**'\n "
},
{
"path": ".github/workflows/test.yml",
"chars": 2608,
"preview": "name: Build and test\non:\n push:\n branches:\n - master\n pull_request:\n paths:\n - '.github/workflows/test"
},
{
"path": ".gitignore",
"chars": 343,
"preview": "/nebula\n/nebula-cert\n/nebula-arm\n/nebula-arm6\n/nebula-darwin\n/nebula.exe\n/nebula-cert.exe\n**/coverage.out\n**/cover.out\n/"
},
{
"path": ".golangci.yaml",
"chars": 381,
"preview": "version: \"2\"\nlinters:\n default: none\n enable:\n - testifylint\n exclusions:\n generated: lax\n presets:\n - "
},
{
"path": "AUTHORS",
"chars": 295,
"preview": "# This is the official list of Nebula authors for copyright purposes.\n\n# Names should be added to this file as:\n# Name o"
},
{
"path": "CHANGELOG.md",
"chars": 30257,
"preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
},
{
"path": "CODEOWNERS",
"chars": 18,
"preview": "#ECCN:Open Source\n"
},
{
"path": "LICENSE",
"chars": 1088,
"preview": "MIT License\n\nCopyright (c) 2018-2019 Slack Technologies, Inc.\n\nPermission is hereby granted, free of charge, to any pers"
},
{
"path": "LOGGING.md",
"chars": 1636,
"preview": "### Logging conventions\n\nA log message (the string/format passed to `Info`, `Error`, `Debug` etc, as well as their `Spri"
},
{
"path": "Makefile",
"chars": 6958,
"preview": "NEBULA_CMD_PATH = \"./cmd/nebula\"\nCGO_ENABLED = 0\nexport CGO_ENABLED\n\n# Set up OS specific bits\nifeq ($(OS),Windows_NT)\n\t"
},
{
"path": "README.md",
"chars": 8060,
"preview": "## What is Nebula?\nNebula is a scalable overlay networking tool with a focus on performance, simplicity and security.\nIt"
},
{
"path": "SECURITY.md",
"chars": 390,
"preview": "Security Policy\n===============\n\nReporting a Vulnerability\n-------------------------\n\nIf you believe you have found a se"
},
{
"path": "allow_list.go",
"chars": 7413,
"preview": "package nebula\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"regexp\"\n\n\t\"github.com/gaissmai/bart\"\n\t\"github.com/slackhq/nebula/config\"\n"
},
{
"path": "allow_list_test.go",
"chars": 4548,
"preview": "package nebula\n\nimport (\n\t\"net/netip\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/gaissmai/bart\"\n\t\"github.com/slackhq/nebula/conf"
},
{
"path": "bits.go",
"chars": 3335,
"preview": "package nebula\n\nimport (\n\t\"github.com/rcrowley/go-metrics\"\n\t\"github.com/sirupsen/logrus\"\n)\n\ntype Bits struct {\n\tlength "
},
{
"path": "bits_test.go",
"chars": 9641,
"preview": "package nebula\n\nimport (\n\t\"testing\"\n\n\t\"github.com/slackhq/nebula/test\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc Tes"
},
{
"path": "boring.go",
"chars": 100,
"preview": "//go:build boringcrypto\n\npackage nebula\n\nimport \"crypto/boring\"\n\nvar boringEnabled = boring.Enabled\n"
},
{
"path": "calculated_remote.go",
"chars": 4286,
"preview": "package nebula\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"net/netip\"\n\t\"strconv\"\n\n\t\"github.com/gaissmai/bart\"\n\t"
},
{
"path": "calculated_remote_test.go",
"chars": 2646,
"preview": "package nebula\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/re"
},
{
"path": "cert/Makefile",
"chars": 233,
"preview": "GO111MODULE = on\nexport GO111MODULE\n\ncert_v1.pb.go: cert_v1.proto .FORCE\n\tgo build google.golang.org/protobuf/cmd/protoc"
},
{
"path": "cert/README.md",
"chars": 655,
"preview": "## `cert`\n\nThis is a library for interacting with `nebula` style certificates and authorities.\n\nThere are now 2 versions"
},
{
"path": "cert/asn1.go",
"chars": 1206,
"preview": "package cert\n\nimport (\n\t\"golang.org/x/crypto/cryptobyte\"\n\t\"golang.org/x/crypto/cryptobyte/asn1\"\n)\n\n// readOptionalASN1Bo"
},
{
"path": "cert/ca_pool.go",
"chars": 8908,
"preview": "package cert\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n)\n\ntype CAPool struct {\n\tCAs "
},
{
"path": "cert/ca_pool_test.go",
"chars": 26876,
"preview": "package cert\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/slackhq/nebula/cert/p256\"\n\t\"github.com/stretchr/tes"
},
{
"path": "cert/cert.go",
"chars": 6016,
"preview": "package cert\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/slackhq/nebula/cert/p256\"\n)\n\ntype Version uint8\n\nconst "
},
{
"path": "cert/cert_v1.go",
"chars": 12843,
"preview": "package cert\n\nimport (\n\t\"bytes\"\n\t\"crypto/ecdh\"\n\t\"crypto/ecdsa\"\n\t\"crypto/ed25519\"\n\t\"crypto/elliptic\"\n\t\"crypto/sha256\"\n\t\"e"
},
{
"path": "cert/cert_v1.pb.go",
"chars": 21128,
"preview": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.34.2\n// \tprotoc v3.21.5\n// sou"
},
{
"path": "cert/cert_v1.proto",
"chars": 1160,
"preview": "syntax = \"proto3\";\npackage cert;\n\noption go_package = \"github.com/slackhq/nebula/cert\";\n\n//import \"google/protobuf/times"
},
{
"path": "cert/cert_v1_test.go",
"chars": 12090,
"preview": "package cert\n\nimport (\n\t\"crypto/ed25519\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/slackhq/nebula/test\"\n\t\"git"
},
{
"path": "cert/cert_v2.asn1",
"chars": 1124,
"preview": "Nebula DEFINITIONS AUTOMATIC TAGS ::= BEGIN\n\nName ::= UTF8String (SIZE (1..253))\nTime ::= INTEGER (0..184467440737095516"
},
{
"path": "cert/cert_v2.go",
"chars": 18674,
"preview": "package cert\n\nimport (\n\t\"bytes\"\n\t\"crypto/ecdh\"\n\t\"crypto/ecdsa\"\n\t\"crypto/ed25519\"\n\t\"crypto/elliptic\"\n\t\"crypto/sha256\"\n\t\"e"
},
{
"path": "cert/cert_v2_test.go",
"chars": 13272,
"preview": "package cert\n\nimport (\n\t\"crypto/ed25519\"\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\t\"git"
},
{
"path": "cert/crypto.go",
"chars": 8707,
"preview": "package cert\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/ed25519\"\n\t\"crypto/rand\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"io\"\n\t\"ma"
},
{
"path": "cert/crypto_test.go",
"chars": 4279,
"preview": "package cert\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang"
},
{
"path": "cert/errors.go",
"chars": 2553,
"preview": "package cert\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nvar (\n\tErrBadFormat = errors.New(\"bad wire format\")\n\tErrRoot"
},
{
"path": "cert/helper_test.go",
"chars": 3329,
"preview": "package cert\n\nimport (\n\t\"crypto/ecdh\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"io\"\n\t\"net/netip\"\n\t\"time\"\n\n\t\"go"
},
{
"path": "cert/p256/p256.go",
"chars": 2596,
"preview": "package p256\n\nimport (\n\t\"crypto/elliptic\"\n\t\"errors\"\n\t\"math/big\"\n\n\t\"filippo.io/bigmod\"\n\n\t\"golang.org/x/crypto/cryptobyte\""
},
{
"path": "cert/p256/p256_test.go",
"chars": 565,
"preview": "package p256\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/requi"
},
{
"path": "cert/pem.go",
"chars": 6113,
"preview": "package cert\n\nimport (\n\t\"encoding/pem\"\n\t\"fmt\"\n\n\t\"golang.org/x/crypto/ed25519\"\n)\n\nconst ( //cert banners\n\tCertificateBann"
},
{
"path": "cert/pem_test.go",
"chars": 11303,
"preview": "package cert\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc "
},
{
"path": "cert/sign.go",
"chars": 4482,
"preview": "package cert\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/ed25519\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"net"
},
{
"path": "cert/sign_test.go",
"chars": 3959,
"preview": "package cert\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/ed25519\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"tim"
},
{
"path": "cert_test/cert.go",
"chars": 4003,
"preview": "package cert_test\n\nimport (\n\t\"crypto/ecdh\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"io\"\n\t\"net/netip\"\n\t\"time\"\n"
},
{
"path": "cmd/nebula/main.go",
"chars": 1505,
"preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime/debug\"\n\t\"strings\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/slac"
},
{
"path": "cmd/nebula/notify_linux.go",
"chars": 1117,
"preview": "package main\n\nimport (\n\t\"net\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// SdNotifyReady tells systemd the service"
},
{
"path": "cmd/nebula/notify_notlinux.go",
"chars": 156,
"preview": "//go:build !linux\n// +build !linux\n\npackage main\n\nimport \"github.com/sirupsen/logrus\"\n\nfunc notifyReady(_ *logrus.Logger"
},
{
"path": "cmd/nebula-cert/ca.go",
"chars": 10352,
"preview": "package main\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net/netip\"\n\t\"os\""
},
{
"path": "cmd/nebula-cert/ca_test.go",
"chars": 9799,
"preview": "//go:build !windows\n// +build !windows\n\npackage main\n\nimport (\n\t\"bytes\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"os\"\n\t\"strings\"\n\t\"tes"
},
{
"path": "cmd/nebula-cert/keygen.go",
"chars": 2610,
"preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/slackhq/nebula/pkclient\"\n\n\t\"github.com/slackhq/nebula/ce"
},
{
"path": "cmd/nebula-cert/keygen_test.go",
"chars": 2900,
"preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/slackhq/nebula/cert\"\n\t\"github.com/stretchr/testify/assert"
},
{
"path": "cmd/nebula-cert/main.go",
"chars": 3072,
"preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"runtime/debug\"\n\t\"strings\"\n)\n\n// A version string that can be set wit"
},
{
"path": "cmd/nebula-cert/main_test.go",
"chars": 1918,
"preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github."
},
{
"path": "cmd/nebula-cert/p11_cgo.go",
"chars": 232,
"preview": "//go:build cgo && pkcs11\n\npackage main\n\nimport (\n\t\"flag\"\n)\n\nfunc p11Supported() bool {\n\treturn true\n}\n\nfunc p11Flag(set "
},
{
"path": "cmd/nebula-cert/p11_stub.go",
"chars": 177,
"preview": "//go:build !cgo || !pkcs11\n\npackage main\n\nimport (\n\t\"flag\"\n)\n\nfunc p11Supported() bool {\n\treturn false\n}\n\nfunc p11Flag(s"
},
{
"path": "cmd/nebula-cert/passwords.go",
"chars": 489,
"preview": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"golang.org/x/term\"\n)\n\nvar ErrNoTerminal = errors.New(\"cannot read passw"
},
{
"path": "cmd/nebula-cert/passwords_test.go",
"chars": 176,
"preview": "package main\n\ntype StubPasswordReader struct {\n\tpassword []byte\n\terr error\n}\n\nfunc (pr *StubPasswordReader) ReadPas"
},
{
"path": "cmd/nebula-cert/print.go",
"chars": 2400,
"preview": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/skip2/go-qrcode\"\n\t\"github.co"
},
{
"path": "cmd/nebula-cert/print_test.go",
"chars": 7500,
"preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"crypto/ed25519\"\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"net/netip\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n"
},
{
"path": "cmd/nebula-cert/sign.go",
"chars": 12146,
"preview": "package main\n\nimport (\n\t\"crypto/ecdh\"\n\t\"crypto/rand\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"os\"\n\t\"strings\"\n\t\"time"
},
{
"path": "cmd/nebula-cert/sign_test.go",
"chars": 19809,
"preview": "//go:build !windows\n// +build !windows\n\npackage main\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"errors\"\n\t\"os\"\n\t\"testing\"\n\t\"time"
},
{
"path": "cmd/nebula-cert/test_darwin.go",
"chars": 117,
"preview": "package main\n\nconst NoSuchFileError = \"no such file or directory\"\nconst NoSuchDirError = \"no such file or directory\"\n"
},
{
"path": "cmd/nebula-cert/test_linux.go",
"chars": 117,
"preview": "package main\n\nconst NoSuchFileError = \"no such file or directory\"\nconst NoSuchDirError = \"no such file or directory\"\n"
},
{
"path": "cmd/nebula-cert/test_windows.go",
"chars": 151,
"preview": "package main\n\nconst NoSuchFileError = \"The system cannot find the file specified.\"\nconst NoSuchDirError = \"The system ca"
},
{
"path": "cmd/nebula-cert/verify.go",
"chars": 2338,
"preview": "package main\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/slackhq/nebula/cert\"\n)\n\ntyp"
},
{
"path": "cmd/nebula-cert/verify_test.go",
"chars": 3937,
"preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/slackhq/nebula/cert\"\n\t\"github.com/"
},
{
"path": "cmd/nebula-service/logs_generic.go",
"chars": 180,
"preview": "//go:build !windows\n// +build !windows\n\npackage main\n\nimport \"github.com/sirupsen/logrus\"\n\nfunc HookLogger(l *logrus.Log"
},
{
"path": "cmd/nebula-service/logs_windows.go",
"chars": 1078,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/kardianos/service\"\n\t\"github.com/sirupsen/logrus\"\n)\n\n// Ho"
},
{
"path": "cmd/nebula-service/main.go",
"chars": 1660,
"preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime/debug\"\n\t\"strings\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/slac"
},
{
"path": "cmd/nebula-service/service.go",
"chars": 2724,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/kardianos/service\"\n\t\"github.com/sirupsen/logru"
},
{
"path": "config/config.go",
"chars": 8212,
"preview": "package config\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strconv\"\n\t\"st"
},
{
"path": "config/config_test.go",
"chars": 5425,
"preview": "package config\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"dario.cat/mergo\"\n\t\"github.com/slackhq/nebula/test\""
},
{
"path": "connection_manager.go",
"chars": 18521,
"preview": "package nebula\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"gi"
},
{
"path": "connection_manager_test.go",
"chars": 14606,
"preview": "package nebula\n\nimport (\n\t\"crypto/ed25519\"\n\t\"crypto/rand\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/flynn/noise\"\n\t\"g"
},
{
"path": "connection_state.go",
"chars": 2406,
"preview": "package nebula\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/flynn/noise\"\n\t\"gith"
},
{
"path": "control.go",
"chars": 9357,
"preview": "package nebula\n\nimport (\n\t\"context\"\n\t\"net/netip\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.c"
},
{
"path": "control_test.go",
"chars": 3604,
"preview": "package nebula\n\nimport (\n\t\"net\"\n\t\"net/netip\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/slackhq/n"
},
{
"path": "control_tester.go",
"chars": 5260,
"preview": "//go:build e2e_testing\n\npackage nebula\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/google/gopacket\"\n\t\"github.com/google/gopacke"
},
{
"path": "dist/windows/wintun/LICENSE.txt",
"chars": 5431,
"preview": "Prebuilt Binaries License\r\n-------------------------\r\n\r\n1. DEFINITIONS. \"Software\" means the precise contents of the \"wi"
},
{
"path": "dist/windows/wintun/README.md",
"chars": 13915,
"preview": "# [Wintun Network Adapter](https://www.wintun.net/)\r\n### TUN Device Driver for Windows\r\n\r\nThis is a layer 3 TUN driver f"
},
{
"path": "dist/windows/wintun/include/wintun.h",
"chars": 10362,
"preview": "/* SPDX-License-Identifier: GPL-2.0 OR MIT\r\n *\r\n * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.\r\n */\r\n\r\n#"
},
{
"path": "dist/wireshark/nebula.lua",
"chars": 4550,
"preview": "local nebula = Proto(\"nebula\", \"nebula\")\n\nlocal default_settings = {\n port = 4242,\n all_ports = false,\n}\n\nneb"
},
{
"path": "dns_server.go",
"chars": 4585,
"preview": "package nebula\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/gaissmai/bart\"\n\t\"github."
},
{
"path": "dns_server_test.go",
"chars": 1619,
"preview": "package nebula\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/miekg/dns\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/sla"
},
{
"path": "docker/Dockerfile",
"chars": 302,
"preview": "FROM gcr.io/distroless/static:latest\n\nARG TARGETOS TARGETARCH\nCOPY build/$TARGETOS-$TARGETARCH/nebula /nebula\nCOPY build"
},
{
"path": "docker/README.md",
"chars": 584,
"preview": "# NebulaOSS/nebula Docker Image\n\n## Building\n\nFrom the root of the repository, run `make docker`.\n\n## Running\n\nTo run th"
},
{
"path": "e2e/doc.go",
"chars": 122,
"preview": "package e2e\n\n// This file exists to allow `go fmt` to traverse here on its own. The build tags were keeping it out befor"
},
{
"path": "e2e/handshakes_test.go",
"chars": 62118,
"preview": "//go:build e2e_testing\n// +build e2e_testing\n\npackage e2e\n\nimport (\n\t\"net/netip\"\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github."
},
{
"path": "e2e/helpers_test.go",
"chars": 10855,
"preview": "//go:build e2e_testing\n// +build e2e_testing\n\npackage e2e\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"os\"\n\t\"strings\"\n\t\"testing"
},
{
"path": "e2e/router/doc.go",
"chars": 125,
"preview": "package router\n\n// This file exists to allow `go fmt` to traverse here on its own. The build tags were keeping it out be"
},
{
"path": "e2e/router/hostmap.go",
"chars": 3703,
"preview": "//go:build e2e_testing\n// +build e2e_testing\n\npackage router\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github."
},
{
"path": "e2e/router/router.go",
"chars": 19500,
"preview": "//go:build e2e_testing\n// +build e2e_testing\n\npackage router\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"os\"\n\t\"path/filep"
},
{
"path": "e2e/tunnels_test.go",
"chars": 13870,
"preview": "//go:build e2e_testing\n// +build e2e_testing\n\npackage e2e\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com"
},
{
"path": "examples/config.yml",
"chars": 21006,
"preview": "# This is the nebula example configuration file. You must edit, at a minimum, the static_host_map, lighthouse, and firew"
},
{
"path": "examples/go_service/main.go",
"chars": 2102,
"preview": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/slackhq/nebula\"\n\t"
},
{
"path": "examples/service_scripts/nebula.init.d.sh",
"chars": 1059,
"preview": "#!/bin/sh\n### BEGIN INIT INFO\n# Provides: nebula\n# Required-Start: $local_fs $network\n# Required-Stop: $"
},
{
"path": "examples/service_scripts/nebula.open-rc",
"chars": 848,
"preview": "#!/sbin/openrc-run\n#\n# nebula service for open-rc systems\n\nextra_commands=\"checkconfig\"\n\n: ${NEBULA_CONFDIR:=${RC_PREFIX"
},
{
"path": "examples/service_scripts/nebula.plist",
"chars": 1109,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "examples/service_scripts/nebula.service",
"chars": 418,
"preview": "[Unit]\nDescription=Nebula overlay networking tool\nWants=basic.target network-online.target nss-lookup.target time-sync.t"
},
{
"path": "firewall/cache.go",
"chars": 1138,
"preview": "package firewall\n\nimport (\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// ConntrackCache is used as a local"
},
{
"path": "firewall/packet.go",
"chars": 1599,
"preview": "package firewall\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/netip\"\n)\n\ntype m = map[string]any\n\nconst (\n\tProtoAny = 0 // "
},
{
"path": "firewall.go",
"chars": 28452,
"preview": "package nebula\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"net/netip\"\n\t\"reflect\"\n\t\"slices\""
},
{
"path": "firewall_test.go",
"chars": 55458,
"preview": "package nebula\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"math\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gaissmai/bart\"\n\t\"githu"
},
{
"path": "go.mod",
"chars": 2161,
"preview": "module github.com/slackhq/nebula\n\ngo 1.25\n\nrequire (\n\tdario.cat/mergo v1.0.2\n\tfilippo.io/bigmod v0.1.0\n\tgithub.com/anmit"
},
{
"path": "go.sum",
"chars": 25281,
"preview": "cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ndario.cat/mergo v1.0.2 h1:85+piFYR1tM"
},
{
"path": "handshake_ix.go",
"chars": 25051,
"preview": "package nebula\n\nimport (\n\t\"bytes\"\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/flynn/noise\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github"
},
{
"path": "handshake_manager.go",
"chars": 23709,
"preview": "package nebula\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/rand\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"sync\"\n"
},
{
"path": "handshake_manager_test.go",
"chars": 2645,
"preview": "package nebula\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/slackhq/nebula/cert\"\n\t\"github.com/slackhq/nebula/"
},
{
"path": "header/header.go",
"chars": 5070,
"preview": "package header\n\nimport (\n\t\"encoding/binary\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n)\n\n//Version 1 header:\n// 0 "
},
{
"path": "header/header_test.go",
"chars": 2976,
"preview": "package header\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/requ"
},
{
"path": "hostmap.go",
"chars": 24295,
"preview": "package nebula\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n"
},
{
"path": "hostmap_test.go",
"chars": 8546,
"preview": "package nebula\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/slackhq/nebula/config\"\n\t\"github.com/slackhq/nebula/test\"\n"
},
{
"path": "hostmap_tester.go",
"chars": 439,
"preview": "//go:build e2e_testing\n\npackage nebula\n\n// This file contains functions used to export information to the e2e testing fr"
},
{
"path": "inside.go",
"chars": 14434,
"preview": "package nebula\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/slackhq/nebula/firewall\"\n\t\"github.com/"
},
{
"path": "inside_bsd.go",
"chars": 123,
"preview": "//go:build darwin || dragonfly || freebsd || netbsd || openbsd\n\npackage nebula\n\nconst immediatelyForwardToSelf bool = tr"
},
{
"path": "inside_generic.go",
"chars": 129,
"preview": "//go:build !darwin && !dragonfly && !freebsd && !netbsd && !openbsd\n\npackage nebula\n\nconst immediatelyForwardToSelf bool"
},
{
"path": "interface.go",
"chars": 14044,
"preview": "package nebula\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"os\"\n\t\"runtime\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"githu"
},
{
"path": "iputil/packet.go",
"chars": 7101,
"preview": "package iputil\n\nimport (\n\t\"encoding/binary\"\n\n\t\"golang.org/x/net/ipv4\"\n)\n\nconst (\n\t// Need 96 bytes for the largest rejec"
},
{
"path": "iputil/packet_test.go",
"chars": 1640,
"preview": "package iputil\n\nimport (\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"golang.org/x/net/ipv4\"\n)\n\nfunc Test_"
},
{
"path": "lighthouse.go",
"chars": 41915,
"preview": "package nebula\n\nimport (\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strconv\"\n\t\"sync\""
},
{
"path": "lighthouse_test.go",
"chars": 18764,
"preview": "package nebula\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/gaissmai/bart\"\n\t\"github.com/sla"
},
{
"path": "logger.go",
"chars": 1176,
"preview": "package nebula\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/slackhq/nebula/config\"\n)\n"
},
{
"path": "main.go",
"chars": 9324,
"preview": "package nebula\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"runtime/debug\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/sirupse"
},
{
"path": "message_metrics.go",
"chars": 2723,
"preview": "package nebula\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/rcrowley/go-metrics\"\n\t\"github.com/slackhq/nebula/header\"\n)\n\ntype MessageMe"
},
{
"path": "nebula.pb.go",
"chars": 68738,
"preview": "// Code generated by protoc-gen-gogo. DO NOT EDIT.\n// source: nebula.proto\n\npackage nebula\n\nimport (\n\tfmt \"fmt\"\n\tproto \""
},
{
"path": "nebula.proto",
"chars": 1746,
"preview": "syntax = \"proto3\";\npackage nebula;\n\noption go_package = \"github.com/slackhq/nebula\";\n\nmessage NebulaMeta {\n enum Messag"
},
{
"path": "noise.go",
"chars": 2075,
"preview": "package nebula\n\nimport (\n\t\"crypto/cipher\"\n\t\"encoding/binary\"\n\t\"errors\"\n\n\t\"github.com/flynn/noise\"\n)\n\ntype endianness int"
},
{
"path": "noiseutil/boring.go",
"chars": 2490,
"preview": "//go:build boringcrypto\n// +build boringcrypto\n\npackage noiseutil\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"encoding/bi"
},
{
"path": "noiseutil/boring_test.go",
"chars": 1708,
"preview": "//go:build boringcrypto\n// +build boringcrypto\n\npackage noiseutil\n\nimport (\n\t\"crypto/boring\"\n\t\"encoding/hex\"\n\t\"testing\"\n"
},
{
"path": "noiseutil/nist.go",
"chars": 1774,
"preview": "package noiseutil\n\nimport (\n\t\"crypto/ecdh\"\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/flynn/noise\"\n)\n\n// DHP256 is the NI"
},
{
"path": "noiseutil/notboring.go",
"chars": 342,
"preview": "//go:build !boringcrypto\n// +build !boringcrypto\n\npackage noiseutil\n\nimport (\n\t\"github.com/flynn/noise\"\n)\n\n// EncryptLoc"
},
{
"path": "noiseutil/notboring_test.go",
"chars": 212,
"preview": "//go:build !boringcrypto\n// +build !boringcrypto\n\npackage noiseutil\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/"
},
{
"path": "noiseutil/pkcs11.go",
"chars": 1268,
"preview": "package noiseutil\n\nimport (\n\t\"crypto/ecdh\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/slackhq/nebula/pkclient\"\n\n\t\"github.com/flynn/"
},
{
"path": "notboring.go",
"chars": 91,
"preview": "//go:build !boringcrypto\n\npackage nebula\n\nvar boringEnabled = func() bool { return false }\n"
},
{
"path": "outside.go",
"chars": 18730,
"preview": "package nebula\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/google/gopacket/layers\"\n\t\"golan"
},
{
"path": "outside_test.go",
"chars": 18341,
"preview": "package nebula\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"net\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/google/gopacket\"\n\t\"git"
},
{
"path": "overlay/device.go",
"chars": 310,
"preview": "package overlay\n\nimport (\n\t\"io\"\n\t\"net/netip\"\n\n\t\"github.com/slackhq/nebula/routing\"\n)\n\ntype Device interface {\n\tio.ReadWr"
},
{
"path": "overlay/route.go",
"chars": 7760,
"preview": "package overlay\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"net/netip\"\n\t\"runtime\"\n\t\"strconv\"\n\n\t\"github.com/gaissmai/bart\"\n\t\"github"
},
{
"path": "overlay/route_test.go",
"chars": 14499,
"preview": "package overlay\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/slackhq/nebula/config\"\n\t\"github.com/slackhq/nebul"
},
{
"path": "overlay/tun.go",
"chars": 3276,
"preview": "package overlay\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/slackhq/nebula/config\"\n"
},
{
"path": "overlay/tun_android.go",
"chars": 2244,
"preview": "//go:build !e2e_testing\n// +build !e2e_testing\n\npackage overlay\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"os\"\n\t\"sync/atomic\""
},
{
"path": "overlay/tun_darwin.go",
"chars": 12734,
"preview": "//go:build !ios && !e2e_testing\n// +build !ios,!e2e_testing\n\npackage overlay\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/neti"
},
{
"path": "overlay/tun_disabled.go",
"chars": 2848,
"preview": "package overlay\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"strings\"\n\n\t\"github.com/rcrowley/go-metrics\"\n\t\"github.com/sirupsen/"
},
{
"path": "overlay/tun_freebsd.go",
"chars": 14707,
"preview": "//go:build !e2e_testing\n// +build !e2e_testing\n\npackage overlay\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net"
},
{
"path": "overlay/tun_ios.go",
"chars": 3202,
"preview": "//go:build ios && !e2e_testing\n// +build ios,!e2e_testing\n\npackage overlay\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\""
},
{
"path": "overlay/tun_linux.go",
"chars": 17827,
"preview": "//go:build !android && !e2e_testing\n// +build !android,!e2e_testing\n\npackage overlay\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net"
},
{
"path": "overlay/tun_linux_test.go",
"chars": 966,
"preview": "//go:build !e2e_testing\n// +build !e2e_testing\n\npackage overlay\n\nimport \"testing\"\n\nvar runAdvMSSTests = []struct {\n\tname"
},
{
"path": "overlay/tun_netbsd.go",
"chars": 13407,
"preview": "//go:build !e2e_testing\n// +build !e2e_testing\n\npackage overlay\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"os\"\n\t\"re"
},
{
"path": "overlay/tun_notwin.go",
"chars": 226,
"preview": "//go:build !windows\n// +build !windows\n\npackage overlay\n\nimport \"syscall\"\n\nfunc ioctl(a1, a2, a3 uintptr) error {\n\t_, _,"
},
{
"path": "overlay/tun_openbsd.go",
"chars": 11224,
"preview": "//go:build !e2e_testing\n// +build !e2e_testing\n\npackage overlay\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"os\"\n\t\"re"
},
{
"path": "overlay/tun_tester.go",
"chars": 3364,
"preview": "//go:build e2e_testing\n// +build e2e_testing\n\npackage overlay\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"os\"\n\t\"sync/atomic\"\n\n"
},
{
"path": "overlay/tun_windows.go",
"chars": 7132,
"preview": "//go:build !e2e_testing\n// +build !e2e_testing\n\npackage overlay\n\nimport (\n\t\"crypto\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"os\"\n\t\"pa"
},
{
"path": "overlay/user.go",
"chars": 1672,
"preview": "package overlay\n\nimport (\n\t\"io\"\n\t\"net/netip\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/slackhq/nebula/config\"\n\t\"github"
},
{
"path": "pkclient/pkclient.go",
"chars": 1753,
"preview": "package pkclient\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\n\t\"github.com/stefanberger/go-pkcs11ur"
},
{
"path": "pkclient/pkclient_cgo.go",
"chars": 6945,
"preview": "//go:build cgo && pkcs11\n\npackage pkclient\n\nimport (\n\t\"encoding/asn1\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"math/big\"\n\n\t\"github.com/"
},
{
"path": "pkclient/pkclient_stub.go",
"chars": 577,
"preview": "//go:build !cgo || !pkcs11\n\npackage pkclient\n\nimport \"errors\"\n\ntype PKClient struct {\n}\n\nvar notImplemented = errors.New"
},
{
"path": "pki.go",
"chars": 14462,
"preview": "package nebula\n\nimport (\n\t\"encoding/binary\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"slices\"\n\t\"stri"
},
{
"path": "punchy.go",
"chars": 2658,
"preview": "package nebula\n\nimport (\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/slackhq/nebula/config\"\n)\n\nty"
},
{
"path": "punchy_test.go",
"chars": 1882,
"preview": "package nebula\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/slackhq/nebula/config\"\n\t\"github.com/slackhq/nebula/test\"\n\t\"git"
},
{
"path": "relay_manager.go",
"chars": 13179,
"preview": "package nebula\n\nimport (\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"sync/atomic\"\n\n\t\"github.com/sirups"
},
{
"path": "remote_list.go",
"chars": 19985,
"preview": "package nebula\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"sort\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"g"
},
{
"path": "remote_list_test.go",
"chars": 8594,
"preview": "package nebula\n\nimport (\n\t\"encoding/binary\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestR"
},
{
"path": "routing/balance.go",
"chars": 1216,
"preview": "package routing\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/slackhq/nebula/firewall\"\n)\n\n// Hashes the packet source and destina"
},
{
"path": "routing/balance_test.go",
"chars": 3649,
"preview": "package routing\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/slackhq/nebula/firewall\"\n\t\"github.com/stretchr/testify/a"
},
{
"path": "routing/gateway.go",
"chars": 1447,
"preview": "package routing\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n)\n\nconst (\n\t// Sentinel value\n\tBucketNotCalculated = -1\n)\n\ntype Gateways ["
},
{
"path": "routing/gateway_test.go",
"chars": 1025,
"preview": "package routing\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRebalance3_2Split(t"
},
{
"path": "service/listener.go",
"chars": 538,
"preview": "package service\n\nimport (\n\t\"io\"\n\t\"net\"\n)\n\ntype tcpListener struct {\n\tport uint16\n\ts *Service\n\taddr *net.TCPAddr"
},
{
"path": "service/service.go",
"chars": 6775,
"preview": "package service\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"math\"\n\t\"net\"\n\t\"net/netip\"\n\t\"strings\"\n\t\"sync\"\n\n\t\""
},
{
"path": "service/service_test.go",
"chars": 3549,
"preview": "package service\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"net/netip\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"dario.cat/mergo\"\n\t\"gith"
},
{
"path": "ssh.go",
"chars": 25972,
"preview": "package nebula\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"maps\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"reflect\""
},
{
"path": "sshd/command.go",
"chars": 3539,
"preview": "package sshd\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/armon/go-radix\"\n)\n\n// CommandFlags is a"
},
{
"path": "sshd/server.go",
"chars": 5479,
"preview": "package sshd\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\n\t\"github.com/armon/go-radix\"\n\t\"github.com/sirupsen/logr"
},
{
"path": "sshd/session.go",
"chars": 3738,
"preview": "package sshd\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/anmitsu/go-shlex\"\n\t\"github.com/armon/go-radix\"\n\t\"github.c"
},
{
"path": "sshd/writer.go",
"chars": 524,
"preview": "package sshd\n\nimport \"io\"\n\ntype StringWriter interface {\n\tWriteLine(string) error\n\tWrite(string) error\n\tWriteBytes([]byt"
},
{
"path": "stats.go",
"chars": 3691,
"preview": "package nebula\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"time\"\n\n\tgraphite \"github.com"
},
{
"path": "test/assert.go",
"chars": 3716,
"preview": "package test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/stretchr/testify/assert"
},
{
"path": "test/logger.go",
"chars": 362,
"preview": "package test\n\nimport (\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\nfunc NewLogger() *logrus.Logger {\n\tl := logrus.New("
},
{
"path": "test/tun.go",
"chars": 713,
"preview": "package test\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"net/netip\"\n\n\t\"github.com/slackhq/nebula/routing\"\n)\n\ntype NoopTun struct{}\n\nfunc"
},
{
"path": "timeout.go",
"chars": 5737,
"preview": "package nebula\n\nimport (\n\t\"sync\"\n\t\"time\"\n)\n\n// How many timer objects should be cached\nconst timerCacheMax = 50000\n\ntype"
},
{
"path": "timeout_test.go",
"chars": 4844,
"preview": "package nebula\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/slackhq/nebula/firewall\"\n\t\"github.com/stretchr/te"
},
{
"path": "udp/conn.go",
"chars": 825,
"preview": "package udp\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/slackhq/nebula/config\"\n)\n\nconst MTU = 9001\n\ntype EncReader func(\n\taddr "
}
]
// ... and 16 more files (download for full content)
About this extraction
This page contains the full source code of the slackhq/nebula GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 216 files (1.3 MB), approximately 428.9k tokens, and a symbol index with 1912 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.