mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-17 07:46:38 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e34e0ccd12 | ||
|
|
95dc9cc16c | ||
|
|
d1c2b3d703 | ||
|
|
966661fe91 | ||
|
|
67ddaade58 | ||
|
|
138cf35e00 | ||
|
|
2555a6c3e8 | ||
|
|
86a66c6202 | ||
|
|
275d364df6 | ||
|
|
a3c5fa1307 | ||
|
|
75a69ca26b | ||
|
|
ae8e3ad6fe | ||
|
|
ff729f6755 | ||
|
|
7e1b20da5d | ||
|
|
d4a3ee9d87 | ||
|
|
49e9113e0f | ||
|
|
3bdfa3cc8e | ||
|
|
8c953c5a2c | ||
|
|
e95f0f7acb | ||
|
|
fa7b413fe7 | ||
|
|
295f0c755a | ||
|
|
a98f6f840a | ||
|
|
faad5a1e98 |
5
.github/workflows/golang-test-darwin.yml
vendored
5
.github/workflows/golang-test-darwin.yml
vendored
@@ -3,15 +3,12 @@ on: [push,pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.18.x]
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
go-version: 1.18.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
|
||||
6
.github/workflows/golang-test-linux.yml
vendored
6
.github/workflows/golang-test-linux.yml
vendored
@@ -5,13 +5,13 @@ jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.18.x]
|
||||
arch: ['386','amd64']
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
go-version: 1.18.x
|
||||
|
||||
|
||||
- name: Cache Go modules
|
||||
@@ -32,4 +32,4 @@ jobs:
|
||||
run: go mod tidy
|
||||
|
||||
- name: Test
|
||||
run: go test -exec 'sudo --preserve-env=CI' -timeout 5m -p 1 ./...
|
||||
run: GOARCH=${{ matrix.arch }} go test -exec 'sudo --preserve-env=CI' -timeout 5m -p 1 ./...
|
||||
|
||||
18
.github/workflows/golang-test-windows.yml
vendored
18
.github/workflows/golang-test-windows.yml
vendored
@@ -18,13 +18,8 @@ jobs:
|
||||
|
||||
test:
|
||||
needs: pre
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.18.x]
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: disable defender
|
||||
run: Set-MpPreference -DisableRealtimeMonitoring $true
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
@@ -32,27 +27,22 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
go-version: 1.18.x
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
%LocalAppData%\go-build
|
||||
~/go/pkg/mod
|
||||
~\go\pkg\mod
|
||||
~\AppData\Local\go-build
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: enable defender
|
||||
run: Set-MpPreference -DisableRealtimeMonitoring $false
|
||||
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: syso
|
||||
path: iface\
|
||||
|
||||
# - name: Install modules
|
||||
# run: go mod tidy
|
||||
|
||||
- name: Test
|
||||
run: go test -tags=load_wgnt_from_rsrc -timeout 5m -p 1 ./...
|
||||
run: go test -tags=load_wgnt_from_rsrc -timeout 5m -p 1 ./...
|
||||
122
.github/workflows/release.yml
vendored
122
.github/workflows/release.yml
vendored
@@ -10,6 +10,7 @@ on:
|
||||
|
||||
env:
|
||||
SIGN_PIPE_VER: "v0.0.3"
|
||||
GORELEASER_VER: "v1.6.3"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
@@ -40,6 +41,9 @@ jobs:
|
||||
-
|
||||
name: Install modules
|
||||
run: go mod tidy
|
||||
-
|
||||
name: check git status
|
||||
run: git --no-pager diff --exit-code
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
@@ -54,45 +58,75 @@ jobs:
|
||||
username: netbirdio
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt update && sudo apt install -y -q libgtk-3-dev libappindicator3-dev libayatana-appindicator3-dev libgl1-mesa-dev xorg-dev gcc-mingw-w64-x86-64
|
||||
|
||||
- name: Install rsrc
|
||||
run: go install github.com/akavel/rsrc@v0.10.2
|
||||
|
||||
- name: Generate windows rsrc
|
||||
run: rsrc -arch amd64 -ico client/ui/netbird.ico -manifest client/ui/manifest.xml -o client/ui/resources_windows_amd64.syso
|
||||
|
||||
-
|
||||
name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: v1.6.3
|
||||
version: ${{ env.GORELEASER_VER }}
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
|
||||
UPLOAD_DEBIAN_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
|
||||
UPLOAD_YUM_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
|
||||
-
|
||||
name: Trigger Windows binaries sign pipeline
|
||||
uses: benc-uk/workflow-dispatch@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
workflow: Sign windows bin and installer
|
||||
repo: netbirdio/sign-pipelines
|
||||
ref: ${{ env.SIGN_PIPE_VER }}
|
||||
token: ${{ secrets.SIGN_GITHUB_TOKEN }}
|
||||
inputs: '{ "tag": "${{ github.ref }}" }'
|
||||
-
|
||||
name: upload non tags for debug purposes
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: build
|
||||
name: release
|
||||
path: dist/
|
||||
retention-days: 3
|
||||
|
||||
|
||||
release_ui:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # It is required for GoReleaser to work properly
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-ui-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-ui-go-
|
||||
|
||||
- name: Install modules
|
||||
run: go mod tidy
|
||||
|
||||
- name: check git status
|
||||
run: git --no-pager diff --exit-code
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt update && sudo apt install -y -q libgtk-3-dev libappindicator3-dev libayatana-appindicator3-dev libgl1-mesa-dev xorg-dev gcc-mingw-w64-x86-64
|
||||
- name: Install rsrc
|
||||
run: go install github.com/akavel/rsrc@v0.10.2
|
||||
- name: Generate windows rsrc
|
||||
run: rsrc -arch amd64 -ico client/ui/netbird.ico -manifest client/ui/manifest.xml -o client/ui/resources_windows_amd64.syso
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: ${{ env.GORELEASER_VER }}
|
||||
args: release --config .goreleaser_ui.yaml --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
|
||||
UPLOAD_DEBIAN_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
|
||||
UPLOAD_YUM_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
|
||||
- name: upload non tags for debug purposes
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: release-ui
|
||||
path: dist/
|
||||
retention-days: 3
|
||||
|
||||
release_ui_darwin:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
-
|
||||
@@ -110,9 +144,9 @@ jobs:
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-ui-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
${{ runner.os }}-ui-go-
|
||||
-
|
||||
name: Install modules
|
||||
run: go mod tidy
|
||||
@@ -121,26 +155,42 @@ jobs:
|
||||
id: goreleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: v1.6.3
|
||||
version: ${{ env.GORELEASER_VER }}
|
||||
args: release --config .goreleaser_ui_darwin.yaml --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
-
|
||||
name: Trigger Darwin App binaries sign pipeline
|
||||
uses: benc-uk/workflow-dispatch@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
name: upload non tags for debug purposes
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
workflow: Sign darwin ui app with dispatch
|
||||
name: release-ui-darwin
|
||||
path: dist/
|
||||
retention-days: 3
|
||||
|
||||
trigger_windows_signer:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [release,release_ui]
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Trigger Windows binaries sign pipeline
|
||||
uses: benc-uk/workflow-dispatch@v1
|
||||
with:
|
||||
workflow: Sign windows bin and installer
|
||||
repo: netbirdio/sign-pipelines
|
||||
ref: ${{ env.SIGN_PIPE_VER }}
|
||||
token: ${{ secrets.SIGN_GITHUB_TOKEN }}
|
||||
inputs: '{ "tag": "${{ github.ref }}" }'
|
||||
|
||||
-
|
||||
name: upload non tags for debug purposes
|
||||
uses: actions/upload-artifact@v2
|
||||
trigger_darwin_signer:
|
||||
runs-on: ubuntu-latest
|
||||
needs: release_ui_darwin
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Trigger Darwin App binaries sign pipeline
|
||||
uses: benc-uk/workflow-dispatch@v1
|
||||
with:
|
||||
name: build-ui-darwin
|
||||
path: dist/
|
||||
retention-days: 3
|
||||
workflow: Sign darwin ui app with dispatch
|
||||
repo: netbirdio/sign-pipelines
|
||||
ref: ${{ env.SIGN_PIPE_VER }}
|
||||
token: ${{ secrets.SIGN_GITHUB_TOKEN }}
|
||||
inputs: '{ "tag": "${{ github.ref }}" }'
|
||||
@@ -13,6 +13,7 @@ builds:
|
||||
- amd64
|
||||
- arm64
|
||||
- mips
|
||||
- 386
|
||||
gomips:
|
||||
- hardfloat
|
||||
- softfloat
|
||||
@@ -21,6 +22,8 @@ builds:
|
||||
goarch: arm64
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
- goos: windows
|
||||
goarch: 386
|
||||
ldflags:
|
||||
- -s -w -X github.com/netbirdio/netbird/client/system.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
@@ -55,88 +58,12 @@ builds:
|
||||
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
|
||||
- id: netbird-ui
|
||||
dir: client/ui
|
||||
binary: netbird-ui
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
ldflags:
|
||||
- -s -w -X github.com/netbirdio/netbird/client/system.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
|
||||
- id: netbird-ui-windows
|
||||
dir: client/ui
|
||||
binary: netbird-ui
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=x86_64-w64-mingw32-gcc
|
||||
goos:
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
ldflags:
|
||||
- -s -w -X github.com/netbirdio/netbird/client/system.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
|
||||
- -H windowsgui
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
|
||||
archives:
|
||||
- builds:
|
||||
- netbird
|
||||
- id: linux-arch
|
||||
name_template: "{{ .ProjectName }}-ui-linux_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
||||
builds:
|
||||
- netbird-ui
|
||||
- id: windows-arch
|
||||
name_template: "{{ .ProjectName }}-ui-windows_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
||||
builds:
|
||||
- netbird-ui-windows
|
||||
|
||||
nfpms:
|
||||
|
||||
- maintainer: Netbird <dev@netbird.io>
|
||||
description: Netbird client UI.
|
||||
homepage: https://netbird.io/
|
||||
id: netbird-ui-deb
|
||||
package_name: netbird-ui
|
||||
builds:
|
||||
- netbird-ui
|
||||
formats:
|
||||
- deb
|
||||
contents:
|
||||
- src: client/ui/netbird.desktop
|
||||
dst: /usr/share/applications/netbird.desktop
|
||||
- src: client/ui/disconnected.png
|
||||
dst: /usr/share/pixmaps/netbird.png
|
||||
dependencies:
|
||||
- libayatana-appindicator3-1
|
||||
- libgtk-3-dev
|
||||
- libappindicator3-dev
|
||||
- netbird
|
||||
|
||||
- maintainer: Netbird <dev@netbird.io>
|
||||
description: Netbird client UI.
|
||||
homepage: https://netbird.io/
|
||||
id: netbird-ui-rpm
|
||||
package_name: netbird-ui
|
||||
builds:
|
||||
- netbird-ui
|
||||
formats:
|
||||
- rpm
|
||||
contents:
|
||||
- src: client/ui/netbird.desktop
|
||||
dst: /usr/share/applications/netbird.desktop
|
||||
- src: client/ui/disconnected.png
|
||||
dst: /usr/share/pixmaps/netbird.png
|
||||
dependencies:
|
||||
- libayatana-appindicator3-1
|
||||
- libgtk-3-dev
|
||||
- libappindicator3-dev
|
||||
- netbird
|
||||
|
||||
- maintainer: Netbird <dev@netbird.io>
|
||||
description: Netbird client.
|
||||
homepage: https://netbird.io/
|
||||
@@ -428,7 +355,6 @@ uploads:
|
||||
- name: debian
|
||||
ids:
|
||||
- netbird-deb
|
||||
- netbird-ui-deb
|
||||
mode: archive
|
||||
target: https://pkgs.wiretrustee.com/debian/pool/{{ .ArtifactName }};deb.distribution=stable;deb.component=main;deb.architecture={{ if .Arm }}armhf{{ else }}{{ .Arch }}{{ end }};deb.package=
|
||||
username: dev@wiretrustee.com
|
||||
@@ -437,7 +363,6 @@ uploads:
|
||||
- name: yum
|
||||
ids:
|
||||
- netbird-rpm
|
||||
- netbird-ui-rpm
|
||||
mode: archive
|
||||
target: https://pkgs.wiretrustee.com/yum/{{ .Arch }}{{ if .Arm }}{{ .Arm }}{{ end }}
|
||||
username: dev@wiretrustee.com
|
||||
|
||||
98
.goreleaser_ui.yaml
Normal file
98
.goreleaser_ui.yaml
Normal file
@@ -0,0 +1,98 @@
|
||||
project_name: netbird-ui
|
||||
builds:
|
||||
- id: netbird-ui
|
||||
dir: client/ui
|
||||
binary: netbird-ui
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
ldflags:
|
||||
- -s -w -X github.com/netbirdio/netbird/client/system.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
|
||||
- id: netbird-ui-windows
|
||||
dir: client/ui
|
||||
binary: netbird-ui
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=x86_64-w64-mingw32-gcc
|
||||
goos:
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
ldflags:
|
||||
- -s -w -X github.com/netbirdio/netbird/client/system.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
|
||||
- -H windowsgui
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
|
||||
archives:
|
||||
- id: linux-arch
|
||||
name_template: "{{ .ProjectName }}-linux_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
||||
builds:
|
||||
- netbird-ui
|
||||
- id: windows-arch
|
||||
name_template: "{{ .ProjectName }}-windows_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
||||
builds:
|
||||
- netbird-ui-windows
|
||||
|
||||
nfpms:
|
||||
|
||||
- maintainer: Netbird <dev@netbird.io>
|
||||
description: Netbird client UI.
|
||||
homepage: https://netbird.io/
|
||||
id: netbird-ui-deb
|
||||
package_name: netbird-ui
|
||||
builds:
|
||||
- netbird-ui
|
||||
formats:
|
||||
- deb
|
||||
contents:
|
||||
- src: client/ui/netbird.desktop
|
||||
dst: /usr/share/applications/netbird.desktop
|
||||
- src: client/ui/disconnected.png
|
||||
dst: /usr/share/pixmaps/netbird.png
|
||||
dependencies:
|
||||
- libayatana-appindicator3-1
|
||||
- libgtk-3-dev
|
||||
- libappindicator3-dev
|
||||
- netbird
|
||||
|
||||
- maintainer: Netbird <dev@netbird.io>
|
||||
description: Netbird client UI.
|
||||
homepage: https://netbird.io/
|
||||
id: netbird-ui-rpm
|
||||
package_name: netbird-ui
|
||||
builds:
|
||||
- netbird-ui
|
||||
formats:
|
||||
- rpm
|
||||
contents:
|
||||
- src: client/ui/netbird.desktop
|
||||
dst: /usr/share/applications/netbird.desktop
|
||||
- src: client/ui/disconnected.png
|
||||
dst: /usr/share/pixmaps/netbird.png
|
||||
dependencies:
|
||||
- libayatana-appindicator3-1
|
||||
- libgtk-3-dev
|
||||
- libappindicator3-dev
|
||||
- netbird
|
||||
|
||||
uploads:
|
||||
- name: debian
|
||||
ids:
|
||||
- netbird-ui-deb
|
||||
mode: archive
|
||||
target: https://pkgs.wiretrustee.com/debian/pool/{{ .ArtifactName }};deb.distribution=stable;deb.component=main;deb.architecture={{ if .Arm }}armhf{{ else }}{{ .Arch }}{{ end }};deb.package=
|
||||
username: dev@wiretrustee.com
|
||||
method: PUT
|
||||
|
||||
- name: yum
|
||||
ids:
|
||||
- netbird-ui-rpm
|
||||
mode: archive
|
||||
target: https://pkgs.wiretrustee.com/yum/{{ .Arch }}{{ if .Arm }}{{ .Arm }}{{ end }}
|
||||
username: dev@wiretrustee.com
|
||||
method: PUT
|
||||
@@ -1,6 +1,6 @@
|
||||
<p align="center">
|
||||
<strong>:hatching_chick: New release! Seamless Access Controls</strong>.
|
||||
<a href="https://github.com/netbirdio/netbird/releases/tag/v0.7.0">
|
||||
<strong>:hatching_chick: New release! NetBird Easy SSH</strong>.
|
||||
<a href="https://github.com/netbirdio/netbird/releases/tag/v0.8.0">
|
||||
Learn more
|
||||
</a>
|
||||
</p>
|
||||
@@ -53,8 +53,10 @@ NetBird creates an overlay peer-to-peer network connecting machines automaticall
|
||||
- \[x] Multicloud and hybrid-cloud support.
|
||||
- \[x] Kernel WireGuard usage when possible.
|
||||
- \[x] Access Controls - groups & rules.
|
||||
- \[x] Remote SSH access without managing SSH keys.
|
||||
|
||||
**Coming soon:**
|
||||
- \[ ] Router nodes
|
||||
- \[ ] Private DNS.
|
||||
- \[ ] Mobile clients.
|
||||
- \[ ] Network Activity Monitoring.
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
FROM gcr.io/distroless/base:debug
|
||||
ENV WT_LOG_FILE=console
|
||||
ENV PATH=/sbin:/usr/sbin:/bin:/usr/bin:/busybox
|
||||
SHELL ["/busybox/sh","-c"]
|
||||
RUN sed -i -E 's/(^root:.+)\/sbin\/nologin/\1\/busybox\/sh/g' /etc/passwd
|
||||
ENTRYPOINT [ "/go/bin/netbird","up"]
|
||||
COPY netbird /go/bin/netbird
|
||||
@@ -43,6 +43,8 @@ var loginCmd = &cobra.Command{
|
||||
return fmt.Errorf("get config file: %v", err)
|
||||
}
|
||||
|
||||
config, _ = internal.UpdateOldManagementPort(ctx, config, configPath)
|
||||
|
||||
err = foregroundLogin(ctx, cmd, config, setupKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("foreground login failed: %v", err)
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/netbirdio/netbird/client/internal"
|
||||
"github.com/netbirdio/netbird/client/proto"
|
||||
nbssh "github.com/netbirdio/netbird/client/ssh"
|
||||
"github.com/netbirdio/netbird/util"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -18,7 +17,7 @@ import (
|
||||
|
||||
var (
|
||||
port int
|
||||
user = "netbird"
|
||||
user = "root"
|
||||
host string
|
||||
)
|
||||
|
||||
@@ -57,34 +56,6 @@ var sshCmd = &cobra.Command{
|
||||
|
||||
ctx := internal.CtxInitState(cmd.Context())
|
||||
|
||||
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to daemon error: %v\n"+
|
||||
"If the daemon is not running please run: "+
|
||||
"\nnetbird service install \nnetbird service start\n", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := conn.Close()
|
||||
if err != nil {
|
||||
log.Warnf("failed closing dameon gRPC client connection %v", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
client := proto.NewDaemonServiceClient(conn)
|
||||
|
||||
status, err := client.Status(ctx, &proto.StatusRequest{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get daemon status: %v", err)
|
||||
}
|
||||
|
||||
if status.Status != string(internal.StatusConnected) {
|
||||
// todo maybe automatically start it?
|
||||
cmd.Printf("You are disconnected from the NetBird network. Please run the UP command first to connect: \n\n" +
|
||||
" netbird up \n\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
config, err := internal.ReadConfig("", "", configPath, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -95,7 +66,8 @@ var sshCmd = &cobra.Command{
|
||||
sshctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
go func() {
|
||||
if err := runSSH(sshctx, host, []byte(config.SSHKey)); err != nil {
|
||||
// blocking
|
||||
if err := runSSH(sshctx, host, []byte(config.SSHKey), cmd); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
cancel()
|
||||
@@ -111,10 +83,16 @@ var sshCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func runSSH(ctx context.Context, addr string, pemKey []byte) error {
|
||||
func runSSH(ctx context.Context, addr string, pemKey []byte, cmd *cobra.Command) error {
|
||||
c, err := nbssh.DialWithKey(fmt.Sprintf("%s:%d", addr, port), user, pemKey)
|
||||
if err != nil {
|
||||
return err
|
||||
cmd.Printf("Error: %v\n", err)
|
||||
cmd.Printf("Couldn't connect. " +
|
||||
"You might be disconnected from the NetBird network, or the NetBird agent isn't running.\n" +
|
||||
"Run the status command: \n\n" +
|
||||
" netbird status\n\n" +
|
||||
"It might also be that the SSH server is disabled on the agent you are trying to connect to.\n")
|
||||
return nil
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
|
||||
@@ -3,13 +3,23 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/netbirdio/netbird/client/internal"
|
||||
"github.com/netbirdio/netbird/client/internal/peer"
|
||||
"github.com/netbirdio/netbird/client/proto"
|
||||
nbStatus "github.com/netbirdio/netbird/client/status"
|
||||
"github.com/netbirdio/netbird/util"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc/status"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal"
|
||||
"github.com/netbirdio/netbird/client/proto"
|
||||
var (
|
||||
detailFlag bool
|
||||
ipsFilter []string
|
||||
statusFilter string
|
||||
ipsFilterMap map[string]struct{}
|
||||
)
|
||||
|
||||
var statusCmd = &cobra.Command{
|
||||
@@ -20,7 +30,12 @@ var statusCmd = &cobra.Command{
|
||||
|
||||
cmd.SetOut(cmd.OutOrStdout())
|
||||
|
||||
err := util.InitLog(logLevel, "console")
|
||||
err := parseFilters()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = util.InitLog(logLevel, "console")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed initializing log %v", err)
|
||||
}
|
||||
@@ -35,21 +50,247 @@ var statusCmd = &cobra.Command{
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
resp, err := proto.NewDaemonServiceClient(conn).Status(cmd.Context(), &proto.StatusRequest{})
|
||||
resp, err := proto.NewDaemonServiceClient(conn).Status(cmd.Context(), &proto.StatusRequest{GetFullPeerStatus: true})
|
||||
if err != nil {
|
||||
return fmt.Errorf("status failed: %v", status.Convert(err).Message())
|
||||
}
|
||||
|
||||
cmd.Printf("Status: %s\n\n", resp.GetStatus())
|
||||
daemonStatus := fmt.Sprintf("Daemon status: %s\n", resp.GetStatus())
|
||||
if resp.GetStatus() == string(internal.StatusNeedsLogin) || resp.GetStatus() == string(internal.StatusLoginFailed) {
|
||||
|
||||
cmd.Printf("Run UP command to log in with SSO (interactive login):\n\n" +
|
||||
" netbird up \n\n" +
|
||||
"If you are running a self-hosted version and no SSO provider has been configured in your Management Server,\n" +
|
||||
"you can use a setup-key:\n\n netbird up --management-url <YOUR_MANAGEMENT_URL> --setup-key <YOUR_SETUP_KEY>\n\n" +
|
||||
"More info: https://www.netbird.io/docs/overview/setup-keys\n\n")
|
||||
cmd.Printf("%s\n"+
|
||||
"Run UP command to log in with SSO (interactive login):\n\n"+
|
||||
" netbird up \n\n"+
|
||||
"If you are running a self-hosted version and no SSO provider has been configured in your Management Server,\n"+
|
||||
"you can use a setup-key:\n\n netbird up --management-url <YOUR_MANAGEMENT_URL> --setup-key <YOUR_SETUP_KEY>\n\n"+
|
||||
"More info: https://www.netbird.io/docs/overview/setup-keys\n\n",
|
||||
daemonStatus,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
pbFullStatus := resp.GetFullStatus()
|
||||
fullStatus := fromProtoFullStatus(pbFullStatus)
|
||||
|
||||
cmd.Print(parseFullStatus(fullStatus, detailFlag, daemonStatus))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
ipsFilterMap = make(map[string]struct{})
|
||||
statusCmd.PersistentFlags().BoolVarP(&detailFlag, "detail", "d", false, "display detailed status information")
|
||||
statusCmd.PersistentFlags().StringSliceVar(&ipsFilter, "filter-by-ips", []string{}, "filters the detailed output by a list of one or more IPs, e.g. --filter-by-ips 100.64.0.100,100.64.0.200")
|
||||
statusCmd.PersistentFlags().StringVar(&statusFilter, "filter-by-status", "", "filters the detailed output by connection status(connected|disconnected), e.g. --filter-by-status connected")
|
||||
}
|
||||
|
||||
func parseFilters() error {
|
||||
switch strings.ToLower(statusFilter) {
|
||||
case "", "disconnected", "connected":
|
||||
default:
|
||||
return fmt.Errorf("wrong status filter, should be one of connected|disconnected, got: %s", statusFilter)
|
||||
}
|
||||
|
||||
if len(ipsFilter) > 0 {
|
||||
for _, addr := range ipsFilter {
|
||||
_, err := netip.ParseAddr(addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("got an invalid IP address in the filter: address %s, error %s", addr, err)
|
||||
}
|
||||
ipsFilterMap[addr] = struct{}{}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fromProtoFullStatus(pbFullStatus *proto.FullStatus) nbStatus.FullStatus {
|
||||
var fullStatus nbStatus.FullStatus
|
||||
managementState := pbFullStatus.GetManagementState()
|
||||
fullStatus.ManagementState.URL = managementState.GetURL()
|
||||
fullStatus.ManagementState.Connected = managementState.GetConnected()
|
||||
|
||||
signalState := pbFullStatus.GetSignalState()
|
||||
fullStatus.SignalState.URL = signalState.GetURL()
|
||||
fullStatus.SignalState.Connected = signalState.GetConnected()
|
||||
|
||||
localPeerState := pbFullStatus.GetLocalPeerState()
|
||||
fullStatus.LocalPeerState.IP = localPeerState.GetIP()
|
||||
fullStatus.LocalPeerState.PubKey = localPeerState.GetPubKey()
|
||||
fullStatus.LocalPeerState.KernelInterface = localPeerState.GetKernelInterface()
|
||||
|
||||
var peersState []nbStatus.PeerState
|
||||
|
||||
for _, pbPeerState := range pbFullStatus.GetPeers() {
|
||||
timeLocal := pbPeerState.GetConnStatusUpdate().AsTime().Local()
|
||||
peerState := nbStatus.PeerState{
|
||||
IP: pbPeerState.GetIP(),
|
||||
PubKey: pbPeerState.GetPubKey(),
|
||||
ConnStatus: pbPeerState.GetConnStatus(),
|
||||
ConnStatusUpdate: timeLocal,
|
||||
Relayed: pbPeerState.GetRelayed(),
|
||||
Direct: pbPeerState.GetDirect(),
|
||||
LocalIceCandidateType: pbPeerState.GetLocalIceCandidateType(),
|
||||
RemoteIceCandidateType: pbPeerState.GetRemoteIceCandidateType(),
|
||||
}
|
||||
peersState = append(peersState, peerState)
|
||||
}
|
||||
|
||||
fullStatus.Peers = peersState
|
||||
|
||||
return fullStatus
|
||||
}
|
||||
|
||||
func parseFullStatus(fullStatus nbStatus.FullStatus, printDetail bool, daemonStatus string) string {
|
||||
var (
|
||||
managementStatusURL = ""
|
||||
signalStatusURL = ""
|
||||
managementConnString = "Disconnected"
|
||||
signalConnString = "Disconnected"
|
||||
interfaceTypeString = "Userspace"
|
||||
)
|
||||
|
||||
if printDetail {
|
||||
managementStatusURL = fmt.Sprintf(" to %s", fullStatus.ManagementState.URL)
|
||||
signalStatusURL = fmt.Sprintf(" to %s", fullStatus.SignalState.URL)
|
||||
}
|
||||
|
||||
if fullStatus.ManagementState.Connected {
|
||||
managementConnString = "Connected"
|
||||
}
|
||||
|
||||
if fullStatus.SignalState.Connected {
|
||||
signalConnString = "Connected"
|
||||
}
|
||||
|
||||
interfaceIP := fullStatus.LocalPeerState.IP
|
||||
|
||||
if fullStatus.LocalPeerState.KernelInterface {
|
||||
interfaceTypeString = "Kernel"
|
||||
} else if fullStatus.LocalPeerState.IP == "" {
|
||||
interfaceTypeString = "N/A"
|
||||
interfaceIP = "N/A"
|
||||
}
|
||||
|
||||
parsedPeersString, peersConnected := parsePeers(fullStatus.Peers, printDetail)
|
||||
|
||||
peersCountString := fmt.Sprintf("%d/%d Connected", peersConnected, len(fullStatus.Peers))
|
||||
|
||||
summary := fmt.Sprintf(
|
||||
"%s"+ // daemon status
|
||||
"Management: %s%s\n"+
|
||||
"Signal: %s%s\n"+
|
||||
"NetBird IP: %s\n"+
|
||||
"Interface type: %s\n"+
|
||||
"Peers count: %s\n",
|
||||
daemonStatus,
|
||||
managementConnString,
|
||||
managementStatusURL,
|
||||
signalConnString,
|
||||
signalStatusURL,
|
||||
interfaceIP,
|
||||
interfaceTypeString,
|
||||
peersCountString,
|
||||
)
|
||||
|
||||
if printDetail {
|
||||
return fmt.Sprintf(
|
||||
"Peers detail:"+
|
||||
"%s\n"+
|
||||
"%s",
|
||||
parsedPeersString,
|
||||
summary,
|
||||
)
|
||||
}
|
||||
return summary
|
||||
}
|
||||
|
||||
func parsePeers(peers []nbStatus.PeerState, printDetail bool) (string, int) {
|
||||
var (
|
||||
peersString = ""
|
||||
peersConnected = 0
|
||||
)
|
||||
|
||||
if len(peers) > 0 {
|
||||
sort.SliceStable(peers, func(i, j int) bool {
|
||||
iAddr, _ := netip.ParseAddr(peers[i].IP)
|
||||
jAddr, _ := netip.ParseAddr(peers[j].IP)
|
||||
return iAddr.Compare(jAddr) == -1
|
||||
})
|
||||
}
|
||||
|
||||
connectedStatusString := peer.StatusConnected.String()
|
||||
|
||||
for _, peerState := range peers {
|
||||
peerConnectionStatus := false
|
||||
if peerState.ConnStatus == connectedStatusString {
|
||||
peersConnected = peersConnected + 1
|
||||
peerConnectionStatus = true
|
||||
}
|
||||
|
||||
if printDetail {
|
||||
|
||||
if skipDetailByFilters(peerState, peerConnectionStatus) {
|
||||
continue
|
||||
}
|
||||
|
||||
localICE := "-"
|
||||
remoteICE := "-"
|
||||
connType := "-"
|
||||
|
||||
if peerConnectionStatus {
|
||||
localICE = peerState.LocalIceCandidateType
|
||||
remoteICE = peerState.RemoteIceCandidateType
|
||||
connType = "P2P"
|
||||
if peerState.Relayed {
|
||||
connType = "Relayed"
|
||||
}
|
||||
}
|
||||
|
||||
peerString := fmt.Sprintf(
|
||||
"\n Peer:\n"+
|
||||
" NetBird IP: %s\n"+
|
||||
" Public key: %s\n"+
|
||||
" Status: %s\n"+
|
||||
" -- detail --\n"+
|
||||
" Connection type: %s\n"+
|
||||
" Direct: %t\n"+
|
||||
" ICE candidate (Local/Remote): %s/%s\n"+
|
||||
" Last connection update: %s\n",
|
||||
peerState.IP,
|
||||
peerState.PubKey,
|
||||
peerState.ConnStatus,
|
||||
connType,
|
||||
peerState.Direct,
|
||||
localICE,
|
||||
remoteICE,
|
||||
peerState.ConnStatusUpdate.Format("2006-01-02 15:04:05"),
|
||||
)
|
||||
|
||||
peersString = peersString + peerString
|
||||
}
|
||||
}
|
||||
return peersString, peersConnected
|
||||
}
|
||||
|
||||
func skipDetailByFilters(peerState nbStatus.PeerState, isConnected bool) bool {
|
||||
statusEval := false
|
||||
ipEval := false
|
||||
|
||||
if statusFilter != "" {
|
||||
lowerStatusFilter := strings.ToLower(statusFilter)
|
||||
if lowerStatusFilter == "disconnected" && isConnected {
|
||||
statusEval = true
|
||||
} else if lowerStatusFilter == "connected" && !isConnected {
|
||||
statusEval = true
|
||||
}
|
||||
}
|
||||
|
||||
if len(ipsFilter) > 0 {
|
||||
_, ok := ipsFilterMap[peerState.IP]
|
||||
if !ok {
|
||||
ipEval = true
|
||||
}
|
||||
}
|
||||
return statusEval || ipEval
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/netbirdio/netbird/client/internal"
|
||||
"github.com/netbirdio/netbird/client/proto"
|
||||
nbStatus "github.com/netbirdio/netbird/client/status"
|
||||
"github.com/netbirdio/netbird/util"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -39,6 +40,8 @@ var upCmd = &cobra.Command{
|
||||
return fmt.Errorf("get config file: %v", err)
|
||||
}
|
||||
|
||||
config, _ = internal.UpdateOldManagementPort(ctx, config, configPath)
|
||||
|
||||
err = foregroundLogin(ctx, cmd, config, setupKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("foreground login failed: %v", err)
|
||||
@@ -47,7 +50,7 @@ var upCmd = &cobra.Command{
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithCancel(ctx)
|
||||
SetupCloseHandler(ctx, cancel)
|
||||
return internal.RunClient(ctx, config)
|
||||
return internal.RunClient(ctx, config, nbStatus.NewRecorder())
|
||||
}
|
||||
|
||||
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
||||
|
||||
@@ -22,7 +22,7 @@ func ManagementURLDefault() *url.URL {
|
||||
}
|
||||
|
||||
func init() {
|
||||
managementURL, err := parseURL("Management URL", "https://api.wiretrustee.com:33073")
|
||||
managementURL, err := ParseURL("Management URL", "https://api.wiretrustee.com:443")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func createNewConfig(managementURL, adminURL, configPath, preSharedKey string) (
|
||||
}
|
||||
config := &Config{SSHKey: string(pem), PrivateKey: wgKey, WgIface: iface.WgInterfaceDefault, IFaceBlackList: []string{}}
|
||||
if managementURL != "" {
|
||||
URL, err := parseURL("Management URL", managementURL)
|
||||
URL, err := ParseURL("Management URL", managementURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -64,6 +64,14 @@ func createNewConfig(managementURL, adminURL, configPath, preSharedKey string) (
|
||||
config.PreSharedKey = preSharedKey
|
||||
}
|
||||
|
||||
if adminURL != "" {
|
||||
newURL, err := ParseURL("Admin Panel URL", adminURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.AdminURL = newURL
|
||||
}
|
||||
|
||||
config.IFaceBlackList = []string{iface.WgInterfaceDefault, "tun0", "zt", "ZeroTier", "utun", "wg", "ts",
|
||||
"Tailscale", "tailscale"}
|
||||
|
||||
@@ -75,7 +83,8 @@ func createNewConfig(managementURL, adminURL, configPath, preSharedKey string) (
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func parseURL(serviceName, managementURL string) (*url.URL, error) {
|
||||
// ParseURL parses and validates management URL
|
||||
func ParseURL(serviceName, managementURL string) (*url.URL, error) {
|
||||
parsedMgmtURL, err := url.ParseRequestURI(managementURL)
|
||||
if err != nil {
|
||||
log.Errorf("failed parsing management URL %s: [%s]", managementURL, err.Error())
|
||||
@@ -107,7 +116,7 @@ func ReadConfig(managementURL, adminURL, configPath string, preSharedKey *string
|
||||
if managementURL != "" && config.ManagementURL.String() != managementURL {
|
||||
log.Infof("new Management URL provided, updated to %s (old value %s)",
|
||||
managementURL, config.ManagementURL)
|
||||
newURL, err := parseURL("Management URL", managementURL)
|
||||
newURL, err := ParseURL("Management URL", managementURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -118,7 +127,7 @@ func ReadConfig(managementURL, adminURL, configPath string, preSharedKey *string
|
||||
if adminURL != "" && (config.AdminURL == nil || config.AdminURL.String() != adminURL) {
|
||||
log.Infof("new Admin Panel URL provided, updated to %s (old value %s)",
|
||||
adminURL, config.AdminURL)
|
||||
newURL, err := parseURL("Admin Panel URL", adminURL)
|
||||
newURL, err := ParseURL("Admin Panel URL", adminURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2,7 +2,11 @@ package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/netbirdio/netbird/client/ssh"
|
||||
nbStatus "github.com/netbirdio/netbird/client/status"
|
||||
mgmtcmd "github.com/netbirdio/netbird/management/cmd"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/client/system"
|
||||
@@ -16,17 +20,17 @@ import (
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
gstatus "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// RunClient with main logic.
|
||||
func RunClient(ctx context.Context, config *Config) error {
|
||||
func RunClient(ctx context.Context, config *Config, statusRecorder *nbStatus.Status) error {
|
||||
backOff := &backoff.ExponentialBackOff{
|
||||
InitialInterval: time.Second,
|
||||
RandomizationFactor: backoff.DefaultRandomizationFactor,
|
||||
Multiplier: backoff.DefaultMultiplier,
|
||||
MaxInterval: 10 * time.Second,
|
||||
MaxElapsedTime: 24 * 3 * time.Hour, // stop the client after 3 days trying (must be a huge problem, e.g permission denied)
|
||||
RandomizationFactor: 1,
|
||||
Multiplier: 1.7,
|
||||
MaxInterval: 15 * time.Second,
|
||||
MaxElapsedTime: 3 * 30 * 24 * time.Hour, // 3 months
|
||||
Stop: backoff.Stop,
|
||||
Clock: backoff.SystemClock,
|
||||
}
|
||||
@@ -40,6 +44,25 @@ func RunClient(ctx context.Context, config *Config) error {
|
||||
}()
|
||||
|
||||
wrapErr := state.Wrap
|
||||
myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey)
|
||||
if err != nil {
|
||||
log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error())
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
var mgmTlsEnabled bool
|
||||
if config.ManagementURL.Scheme == "https" {
|
||||
mgmTlsEnabled = true
|
||||
}
|
||||
|
||||
publicSSHKey, err := ssh.GeneratePublicKey([]byte(config.SSHKey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
managementURL := config.ManagementURL.String()
|
||||
statusRecorder.MarkManagementDisconnected(managementURL)
|
||||
|
||||
operation := func() error {
|
||||
// if context cancelled we not start new backoff cycle
|
||||
select {
|
||||
@@ -49,37 +72,42 @@ func RunClient(ctx context.Context, config *Config) error {
|
||||
}
|
||||
|
||||
state.Set(StatusConnecting)
|
||||
// validate our peer's Wireguard PRIVATE key
|
||||
myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey)
|
||||
if err != nil {
|
||||
log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error())
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
var mgmTlsEnabled bool
|
||||
if config.ManagementURL.Scheme == "https" {
|
||||
mgmTlsEnabled = true
|
||||
}
|
||||
|
||||
engineCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
defer func() {
|
||||
statusRecorder.MarkManagementDisconnected(managementURL)
|
||||
statusRecorder.CleanLocalPeerState()
|
||||
cancel()
|
||||
}()
|
||||
|
||||
publicSSHKey, err := ssh.GeneratePublicKey([]byte(config.SSHKey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// connect (just a connection, no stream yet) and login to Management Service to get an initial global Wiretrustee config
|
||||
mgmClient, loginResp, err := connectToManagement(engineCtx, config.ManagementURL.Host, myPrivateKey, mgmTlsEnabled,
|
||||
publicSSHKey)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
if s, ok := status.FromError(err); ok && s.Code() == codes.PermissionDenied {
|
||||
log.Info("peer registration required. Please run `netbird status` for details")
|
||||
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.PermissionDenied) {
|
||||
state.Set(StatusNeedsLogin)
|
||||
return nil
|
||||
return backoff.Permanent(wrapErr(err)) // unrecoverable error
|
||||
}
|
||||
return wrapErr(err)
|
||||
}
|
||||
statusRecorder.MarkManagementConnected(managementURL)
|
||||
|
||||
localPeerState := nbStatus.LocalPeerState{
|
||||
IP: loginResp.GetPeerConfig().GetAddress(),
|
||||
PubKey: myPrivateKey.PublicKey().String(),
|
||||
KernelInterface: iface.WireguardModExists(),
|
||||
}
|
||||
|
||||
statusRecorder.UpdateLocalPeerState(localPeerState)
|
||||
|
||||
signalURL := fmt.Sprintf("%s://%s",
|
||||
strings.ToLower(loginResp.GetWiretrusteeConfig().GetSignal().GetProtocol().String()),
|
||||
loginResp.GetWiretrusteeConfig().GetSignal().GetUri(),
|
||||
)
|
||||
|
||||
statusRecorder.MarkSignalDisconnected(signalURL)
|
||||
defer statusRecorder.MarkSignalDisconnected(signalURL)
|
||||
|
||||
// with the global Wiretrustee config in hand connect (just a connection, no stream yet) Signal
|
||||
signalClient, err := connectToSignal(engineCtx, loginResp.GetWiretrusteeConfig(), myPrivateKey)
|
||||
@@ -88,6 +116,8 @@ func RunClient(ctx context.Context, config *Config) error {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
statusRecorder.MarkSignalConnected(signalURL)
|
||||
|
||||
peerConfig := loginResp.GetPeerConfig()
|
||||
|
||||
engineConfig, err := createEngineConfig(myPrivateKey, config, peerConfig)
|
||||
@@ -96,7 +126,7 @@ func RunClient(ctx context.Context, config *Config) error {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
engine := NewEngine(engineCtx, cancel, signalClient, mgmClient, engineConfig)
|
||||
engine := NewEngine(engineCtx, cancel, signalClient, mgmClient, engineConfig, statusRecorder)
|
||||
err = engine.Start()
|
||||
if err != nil {
|
||||
log.Errorf("error while starting Netbird Connection Engine: %s", err)
|
||||
@@ -115,6 +145,7 @@ func RunClient(ctx context.Context, config *Config) error {
|
||||
log.Errorf("failed closing Management Service client %v", err)
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
err = signalClient.Close()
|
||||
if err != nil {
|
||||
log.Errorf("failed closing Signal Service client %v", err)
|
||||
@@ -127,7 +158,7 @@ func RunClient(ctx context.Context, config *Config) error {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
log.Info("stopped Netbird client")
|
||||
log.Info("stopped NetBird client")
|
||||
|
||||
if _, err := state.Status(); err == ErrResetConnection {
|
||||
return err
|
||||
@@ -136,9 +167,9 @@ func RunClient(ctx context.Context, config *Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := backoff.Retry(operation, backOff)
|
||||
err = backoff.Retry(operation, backOff)
|
||||
if err != nil {
|
||||
log.Errorf("exiting client retry loop due to unrecoverable error: %s", err)
|
||||
log.Debugf("exiting client retry loop due to unrecoverable error: %s", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -179,7 +210,7 @@ func connectToSignal(ctx context.Context, wtConfig *mgmProto.WiretrusteeConfig,
|
||||
signalClient, err := signal.NewClient(ctx, wtConfig.Signal.Uri, ourPrivateKey, sigTLSEnabled)
|
||||
if err != nil {
|
||||
log.Errorf("error while connecting to the Signal Exchange Service %s: %s", wtConfig.Signal.Uri, err)
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "failed connecting to Signal Service : %s", err)
|
||||
return nil, gstatus.Errorf(codes.FailedPrecondition, "failed connecting to Signal Service : %s", err)
|
||||
}
|
||||
|
||||
return signalClient, nil
|
||||
@@ -190,13 +221,13 @@ func connectToManagement(ctx context.Context, managementAddr string, ourPrivateK
|
||||
log.Debugf("connecting to Management Service %s", managementAddr)
|
||||
client, err := mgm.NewClient(ctx, managementAddr, ourPrivateKey, tlsEnabled)
|
||||
if err != nil {
|
||||
return nil, nil, status.Errorf(codes.FailedPrecondition, "failed connecting to Management Service : %s", err)
|
||||
return nil, nil, gstatus.Errorf(codes.FailedPrecondition, "failed connecting to Management Service : %s", err)
|
||||
}
|
||||
log.Debugf("connected to management server %s", managementAddr)
|
||||
|
||||
serverPublicKey, err := client.GetServerPublicKey()
|
||||
if err != nil {
|
||||
return nil, nil, status.Errorf(codes.FailedPrecondition, "failed while getting Management Service public key: %s", err)
|
||||
return nil, nil, gstatus.Errorf(codes.FailedPrecondition, "failed while getting Management Service public key: %s", err)
|
||||
}
|
||||
|
||||
sysInfo := system.GetInfo(ctx)
|
||||
@@ -209,3 +240,67 @@ func connectToManagement(ctx context.Context, managementAddr string, ourPrivateK
|
||||
|
||||
return client, loginResp, nil
|
||||
}
|
||||
|
||||
// UpdateOldManagementPort checks whether client can switch to the new Management port 443.
|
||||
// If it can switch, then it updates the config and returns a new one. Otherwise, it returns the provided config.
|
||||
// The check is performed only for the NetBird's managed version.
|
||||
func UpdateOldManagementPort(ctx context.Context, config *Config, configPath string) (*Config, error) {
|
||||
|
||||
if config.ManagementURL.Hostname() != ManagementURLDefault().Hostname() {
|
||||
// only do the check for the NetBird's managed version
|
||||
return config, nil
|
||||
}
|
||||
|
||||
var mgmTlsEnabled bool
|
||||
if config.ManagementURL.Scheme == "https" {
|
||||
mgmTlsEnabled = true
|
||||
}
|
||||
|
||||
if !mgmTlsEnabled {
|
||||
// only do the check for HTTPs scheme (the hosted version of the Management service is always HTTPs)
|
||||
return config, nil
|
||||
}
|
||||
|
||||
if mgmTlsEnabled && config.ManagementURL.Port() == fmt.Sprintf("%d", mgmtcmd.ManagementLegacyPort) {
|
||||
|
||||
newURL, err := ParseURL("Management URL", fmt.Sprintf("%s://%s:%d",
|
||||
config.ManagementURL.Scheme, config.ManagementURL.Hostname(), 443))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// here we check whether we could switch from the legacy 33073 port to the new 443
|
||||
log.Infof("attempting to switch from the legacy Management URL %s to the new one %s",
|
||||
config.ManagementURL.String(), newURL.String())
|
||||
key, err := wgtypes.ParseKey(config.PrivateKey)
|
||||
if err != nil {
|
||||
log.Infof("couldn't switch to the new Management %s", newURL.String())
|
||||
return config, err
|
||||
}
|
||||
|
||||
client, err := mgm.NewClient(ctx, newURL.Host, key, mgmTlsEnabled)
|
||||
if err != nil {
|
||||
log.Infof("couldn't switch to the new Management %s", newURL.String())
|
||||
return config, err
|
||||
}
|
||||
defer client.Close() //nolint
|
||||
|
||||
// gRPC check
|
||||
_, err = client.GetServerPublicKey()
|
||||
if err != nil {
|
||||
log.Infof("couldn't switch to the new Management %s", newURL.String())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// everything is alright => update the config
|
||||
newConfig, err := ReadConfig(newURL.String(), "", configPath, nil)
|
||||
if err != nil {
|
||||
log.Infof("couldn't switch to the new Management %s", newURL.String())
|
||||
return config, fmt.Errorf("failed updating config file: %v", err)
|
||||
}
|
||||
log.Infof("successfully switched to the new Management URL: %s", newURL.String())
|
||||
|
||||
return newConfig, nil
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
nbssh "github.com/netbirdio/netbird/client/ssh"
|
||||
nbstatus "github.com/netbirdio/netbird/client/status"
|
||||
"math/rand"
|
||||
"net"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -95,6 +97,8 @@ type Engine struct {
|
||||
|
||||
sshServerFunc func(hostKeyPEM []byte, addr string) (nbssh.Server, error)
|
||||
sshServer nbssh.Server
|
||||
|
||||
statusRecorder *nbstatus.Status
|
||||
}
|
||||
|
||||
// Peer is an instance of the Connection Peer
|
||||
@@ -106,20 +110,22 @@ type Peer struct {
|
||||
// NewEngine creates a new Connection Engine
|
||||
func NewEngine(
|
||||
ctx context.Context, cancel context.CancelFunc,
|
||||
signalClient signal.Client, mgmClient mgm.Client, config *EngineConfig,
|
||||
signalClient signal.Client, mgmClient mgm.Client,
|
||||
config *EngineConfig, statusRecorder *nbstatus.Status,
|
||||
) *Engine {
|
||||
return &Engine{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
signal: signalClient,
|
||||
mgmClient: mgmClient,
|
||||
peerConns: map[string]*peer.Conn{},
|
||||
syncMsgMux: &sync.Mutex{},
|
||||
config: config,
|
||||
STUNs: []*ice.URL{},
|
||||
TURNs: []*ice.URL{},
|
||||
networkSerial: 0,
|
||||
sshServerFunc: nbssh.DefaultSSHServer,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
signal: signalClient,
|
||||
mgmClient: mgmClient,
|
||||
peerConns: map[string]*peer.Conn{},
|
||||
syncMsgMux: &sync.Mutex{},
|
||||
config: config,
|
||||
STUNs: []*ice.URL{},
|
||||
TURNs: []*ice.URL{},
|
||||
networkSerial: 0,
|
||||
sshServerFunc: nbssh.DefaultSSHServer,
|
||||
statusRecorder: statusRecorder,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +175,13 @@ func (e *Engine) Stop() error {
|
||||
}
|
||||
}
|
||||
|
||||
if !isNil(e.sshServer) {
|
||||
err := e.sshServer.Stop()
|
||||
if err != nil {
|
||||
log.Warnf("failed stopping the SSH server: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("stopped Netbird Engine")
|
||||
|
||||
return nil
|
||||
@@ -296,10 +309,17 @@ func (e *Engine) removeAllPeers() error {
|
||||
func (e *Engine) removePeer(peerKey string) error {
|
||||
log.Debugf("removing peer from engine %s", peerKey)
|
||||
|
||||
if e.sshServer != nil {
|
||||
if !isNil(e.sshServer) {
|
||||
e.sshServer.RemoveAuthorizedKey(peerKey)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := e.statusRecorder.RemovePeer(peerKey)
|
||||
if err != nil {
|
||||
log.Warnf("received error when removing peer %s from status recorder: %v", peerKey, err)
|
||||
}
|
||||
}()
|
||||
|
||||
conn, exists := e.peerConns[peerKey]
|
||||
if exists {
|
||||
delete(e.peerConns, peerKey)
|
||||
@@ -422,6 +442,10 @@ func (e *Engine) handleSync(update *mgmProto.SyncResponse) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func isNil(server nbssh.Server) bool {
|
||||
return server == nil || reflect.ValueOf(server).IsNil()
|
||||
}
|
||||
|
||||
func (e *Engine) updateSSH(sshConf *mgmProto.SSHConfig) error {
|
||||
if sshConf.GetSshEnabled() {
|
||||
if runtime.GOOS == "windows" {
|
||||
@@ -429,7 +453,7 @@ func (e *Engine) updateSSH(sshConf *mgmProto.SSHConfig) error {
|
||||
return nil
|
||||
}
|
||||
// start SSH server if it wasn't running
|
||||
if e.sshServer == nil {
|
||||
if isNil(e.sshServer) {
|
||||
//nil sshServer means it has not yet been started
|
||||
var err error
|
||||
e.sshServer, err = e.sshServerFunc(e.config.SSHKey,
|
||||
@@ -454,7 +478,7 @@ func (e *Engine) updateSSH(sshConf *mgmProto.SSHConfig) error {
|
||||
}
|
||||
} else {
|
||||
// Disable SSH server request, so stop it if it was running
|
||||
if e.sshServer != nil {
|
||||
if !isNil(e.sshServer) {
|
||||
err := e.sshServer.Stop()
|
||||
if err != nil {
|
||||
log.Warnf("failed to stop SSH server %v", err)
|
||||
@@ -585,7 +609,7 @@ func (e *Engine) updateNetworkMap(networkMap *mgmProto.NetworkMap) error {
|
||||
}
|
||||
|
||||
// update SSHServer by adding remote peer SSH keys
|
||||
if e.sshServer != nil {
|
||||
if !isNil(e.sshServer) {
|
||||
for _, config := range networkMap.GetRemotePeers() {
|
||||
if config.GetSshConfig() != nil && config.GetSshConfig().GetSshPubKey() != nil {
|
||||
err := e.sshServer.AddAuthorizedKey(config.WgPubKey, string(config.GetSshConfig().GetSshPubKey()))
|
||||
@@ -623,12 +647,17 @@ func (e *Engine) addNewPeer(peerConfig *mgmProto.RemotePeerConfig) error {
|
||||
}
|
||||
e.peerConns[peerKey] = conn
|
||||
|
||||
err = e.statusRecorder.AddPeer(peerKey)
|
||||
if err != nil {
|
||||
log.Warnf("error adding peer %s to status recorder, got error: %v", peerKey, err)
|
||||
}
|
||||
|
||||
go e.connWorker(conn, peerKey)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e Engine) connWorker(conn *peer.Conn, peerKey string) {
|
||||
func (e *Engine) connWorker(conn *peer.Conn, peerKey string) {
|
||||
for {
|
||||
|
||||
// randomize starting time a bit
|
||||
@@ -647,6 +676,13 @@ func (e Engine) connWorker(conn *peer.Conn, peerKey string) {
|
||||
continue
|
||||
}
|
||||
|
||||
// we might have received new STUN and TURN servers meanwhile, so update them
|
||||
e.syncMsgMux.Lock()
|
||||
conf := conn.GetConf()
|
||||
conf.StunTurn = append(e.STUNs, e.TURNs...)
|
||||
conn.UpdateConf(conf)
|
||||
e.syncMsgMux.Unlock()
|
||||
|
||||
err := conn.Open()
|
||||
if err != nil {
|
||||
log.Debugf("connection to peer %s failed: %v", peerKey, err)
|
||||
@@ -693,7 +729,7 @@ func (e Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, er
|
||||
ProxyConfig: proxyConfig,
|
||||
}
|
||||
|
||||
peerConn, err := peer.NewConn(config)
|
||||
peerConn, err := peer.NewConn(config, e.statusRecorder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/netbirdio/netbird/client/ssh"
|
||||
nbstatus "github.com/netbirdio/netbird/client/status"
|
||||
"github.com/netbirdio/netbird/iface"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net"
|
||||
@@ -63,7 +64,7 @@ func TestEngine_SSH(t *testing.T) {
|
||||
WgAddr: "100.64.0.1/24",
|
||||
WgPrivateKey: key,
|
||||
WgPort: 33100,
|
||||
})
|
||||
}, nbstatus.NewRecorder())
|
||||
|
||||
var sshKeysAdded []string
|
||||
var sshPeersRemoved []string
|
||||
@@ -193,7 +194,7 @@ func TestEngine_UpdateNetworkMap(t *testing.T) {
|
||||
WgAddr: "100.64.0.1/24",
|
||||
WgPrivateKey: key,
|
||||
WgPort: 33100,
|
||||
})
|
||||
}, nbstatus.NewRecorder())
|
||||
engine.wgInterface, err = iface.NewWGIFace("utun102", "100.64.0.1/24", iface.DefaultMTU)
|
||||
|
||||
type testCase struct {
|
||||
@@ -373,7 +374,7 @@ func TestEngine_Sync(t *testing.T) {
|
||||
WgAddr: "100.64.0.1/24",
|
||||
WgPrivateKey: key,
|
||||
WgPort: 33100,
|
||||
})
|
||||
}, nbstatus.NewRecorder())
|
||||
|
||||
defer func() {
|
||||
err := engine.Stop()
|
||||
@@ -576,7 +577,7 @@ func createEngine(ctx context.Context, cancel context.CancelFunc, setupKey strin
|
||||
WgPort: wgPort,
|
||||
}
|
||||
|
||||
return NewEngine(ctx, cancel, signalClient, mgmtClient, conf), nil
|
||||
return NewEngine(ctx, cancel, signalClient, mgmtClient, conf, nbstatus.NewRecorder()), nil
|
||||
}
|
||||
|
||||
func startSignal(port int) (*grpc.Server, error) {
|
||||
|
||||
@@ -49,6 +49,7 @@ func Login(ctx context.Context, config *Config, setupKey string, jwtToken string
|
||||
log.Errorf("failed logging-in peer on Management Service : %v", err)
|
||||
return err
|
||||
}
|
||||
log.Infof("peer has successfully logged-in to the Management service %s", config.ManagementURL.String())
|
||||
|
||||
err = mgmClient.Close()
|
||||
if err != nil {
|
||||
@@ -72,8 +73,6 @@ func loginPeer(ctx context.Context, serverPublicKey wgtypes.Key, client *mgm.Grp
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("peer has successfully logged-in to Management Service")
|
||||
|
||||
return loginResp, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package peer
|
||||
|
||||
import (
|
||||
"context"
|
||||
nbStatus "github.com/netbirdio/netbird/client/status"
|
||||
"github.com/netbirdio/netbird/iface"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
"net"
|
||||
@@ -64,6 +65,8 @@ type Conn struct {
|
||||
agent *ice.Agent
|
||||
status ConnStatus
|
||||
|
||||
statusRecorder *nbStatus.Status
|
||||
|
||||
proxy proxy.Proxy
|
||||
}
|
||||
|
||||
@@ -72,9 +75,14 @@ func (conn *Conn) GetConf() ConnConfig {
|
||||
return conn.config
|
||||
}
|
||||
|
||||
// UpdateConf updates the connection config
|
||||
func (conn *Conn) UpdateConf(conf ConnConfig) {
|
||||
conn.config = conf
|
||||
}
|
||||
|
||||
// NewConn creates a new not opened Conn to the remote peer.
|
||||
// To establish a connection run Conn.Open
|
||||
func NewConn(config ConnConfig) (*Conn, error) {
|
||||
func NewConn(config ConnConfig, statusRecorder *nbStatus.Status) (*Conn, error) {
|
||||
return &Conn{
|
||||
config: config,
|
||||
mu: sync.Mutex{},
|
||||
@@ -82,6 +90,7 @@ func NewConn(config ConnConfig) (*Conn, error) {
|
||||
closeCh: make(chan struct{}),
|
||||
remoteOffersCh: make(chan IceCredentials),
|
||||
remoteAnswerCh: make(chan IceCredentials),
|
||||
statusRecorder: statusRecorder,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -157,6 +166,17 @@ func (conn *Conn) reCreateAgent() error {
|
||||
func (conn *Conn) Open() error {
|
||||
log.Debugf("trying to connect to peer %s", conn.config.Key)
|
||||
|
||||
peerState := nbStatus.PeerState{PubKey: conn.config.Key}
|
||||
|
||||
peerState.IP = strings.Split(conn.config.ProxyConfig.AllowedIps, "/")[0]
|
||||
peerState.ConnStatusUpdate = time.Now()
|
||||
peerState.ConnStatus = conn.status.String()
|
||||
|
||||
err := conn.statusRecorder.UpdatePeerState(peerState)
|
||||
if err != nil {
|
||||
log.Warnf("erro while updating the state of peer %s,err: %v", conn.config.Key, err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := conn.cleanup()
|
||||
if err != nil {
|
||||
@@ -165,7 +185,7 @@ func (conn *Conn) Open() error {
|
||||
}
|
||||
}()
|
||||
|
||||
err := conn.reCreateAgent()
|
||||
err = conn.reCreateAgent()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -205,6 +225,15 @@ func (conn *Conn) Open() error {
|
||||
defer conn.notifyDisconnected()
|
||||
conn.mu.Unlock()
|
||||
|
||||
peerState = nbStatus.PeerState{PubKey: conn.config.Key}
|
||||
|
||||
peerState.ConnStatus = conn.status.String()
|
||||
peerState.ConnStatusUpdate = time.Now()
|
||||
err = conn.statusRecorder.UpdatePeerState(peerState)
|
||||
if err != nil {
|
||||
log.Warnf("erro while updating the state of peer %s,err: %v", conn.config.Key, err)
|
||||
}
|
||||
|
||||
err = conn.agent.GatherCandidates()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -224,7 +253,7 @@ func (conn *Conn) Open() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// the connection has been established successfully so we are ready to start the proxy
|
||||
// the ice connection has been established successfully so we are ready to start the proxy
|
||||
err = conn.startProxy(remoteConn)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -259,6 +288,10 @@ func shouldUseProxy(pair *ice.CandidatePair) bool {
|
||||
remoteIsPublic := IsPublicIP(remoteIP)
|
||||
myIsPublic := IsPublicIP(myIp)
|
||||
|
||||
if pair.Local.Type() == ice.CandidateTypeRelay || pair.Remote.Type() == ice.CandidateTypeRelay {
|
||||
return true
|
||||
}
|
||||
|
||||
//one of the hosts has a public IP
|
||||
if remoteIsPublic && pair.Remote.Type() == ice.CandidateTypeHost {
|
||||
return false
|
||||
@@ -296,12 +329,15 @@ func (conn *Conn) startProxy(remoteConn net.Conn) error {
|
||||
return err
|
||||
}
|
||||
|
||||
peerState := nbStatus.PeerState{PubKey: conn.config.Key}
|
||||
useProxy := shouldUseProxy(pair)
|
||||
var p proxy.Proxy
|
||||
if useProxy {
|
||||
p = proxy.NewWireguardProxy(conn.config.ProxyConfig)
|
||||
peerState.Direct = false
|
||||
} else {
|
||||
p = proxy.NewNoProxy(conn.config.ProxyConfig)
|
||||
peerState.Direct = true
|
||||
}
|
||||
conn.proxy = p
|
||||
err = p.Start(remoteConn)
|
||||
@@ -311,6 +347,19 @@ func (conn *Conn) startProxy(remoteConn net.Conn) error {
|
||||
|
||||
conn.status = StatusConnected
|
||||
|
||||
peerState.ConnStatus = conn.status.String()
|
||||
peerState.ConnStatusUpdate = time.Now()
|
||||
peerState.LocalIceCandidateType = pair.Local.Type().String()
|
||||
peerState.RemoteIceCandidateType = pair.Remote.Type().String()
|
||||
if pair.Local.Type() == ice.CandidateTypeRelay || pair.Remote.Type() == ice.CandidateTypeRelay {
|
||||
peerState.Relayed = true
|
||||
}
|
||||
|
||||
err = conn.statusRecorder.UpdatePeerState(peerState)
|
||||
if err != nil {
|
||||
log.Warnf("unable to save peer's state, got error: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -343,6 +392,14 @@ func (conn *Conn) cleanup() error {
|
||||
|
||||
conn.status = StatusDisconnected
|
||||
|
||||
peerState := nbStatus.PeerState{PubKey: conn.config.Key}
|
||||
peerState.ConnStatus = conn.status.String()
|
||||
peerState.ConnStatusUpdate = time.Now()
|
||||
err := conn.statusRecorder.UpdatePeerState(peerState)
|
||||
if err != nil {
|
||||
log.Warnf("error while updating peer's %s state, err: %v", conn.config.Key, err)
|
||||
}
|
||||
|
||||
log.Debugf("cleaned up connection to peer %s", conn.config.Key)
|
||||
|
||||
return nil
|
||||
@@ -367,7 +424,7 @@ func (conn *Conn) SetSignalCandidate(handler func(candidate ice.Candidate) error
|
||||
// and then signals them to the remote peer
|
||||
func (conn *Conn) onICECandidate(candidate ice.Candidate) {
|
||||
if candidate != nil {
|
||||
// log.Debugf("discovered local candidate %s", candidate.String())
|
||||
log.Debugf("discovered local candidate %s", candidate.String())
|
||||
go func() {
|
||||
err := conn.signalCandidate(candidate)
|
||||
if err != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@ package peer
|
||||
import (
|
||||
"github.com/magiconair/properties/assert"
|
||||
"github.com/netbirdio/netbird/client/internal/proxy"
|
||||
nbstatus "github.com/netbirdio/netbird/client/status"
|
||||
"github.com/netbirdio/netbird/iface"
|
||||
"github.com/pion/ice/v2"
|
||||
"sync"
|
||||
@@ -32,7 +33,7 @@ func TestNewConn_interfaceFilter(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConn_GetKey(t *testing.T) {
|
||||
conn, err := NewConn(connConf)
|
||||
conn, err := NewConn(connConf, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -44,7 +45,7 @@ func TestConn_GetKey(t *testing.T) {
|
||||
|
||||
func TestConn_OnRemoteOffer(t *testing.T) {
|
||||
|
||||
conn, err := NewConn(connConf)
|
||||
conn, err := NewConn(connConf, nbstatus.NewRecorder())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -74,7 +75,7 @@ func TestConn_OnRemoteOffer(t *testing.T) {
|
||||
|
||||
func TestConn_OnRemoteAnswer(t *testing.T) {
|
||||
|
||||
conn, err := NewConn(connConf)
|
||||
conn, err := NewConn(connConf, nbstatus.NewRecorder())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -103,7 +104,7 @@ func TestConn_OnRemoteAnswer(t *testing.T) {
|
||||
}
|
||||
func TestConn_Status(t *testing.T) {
|
||||
|
||||
conn, err := NewConn(connConf)
|
||||
conn, err := NewConn(connConf, nbstatus.NewRecorder())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -130,7 +131,7 @@ func TestConn_Status(t *testing.T) {
|
||||
|
||||
func TestConn_Close(t *testing.T) {
|
||||
|
||||
conn, err := NewConn(connConf)
|
||||
conn, err := NewConn(connConf, nbstatus.NewRecorder())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ type ConnStatus int
|
||||
func (s ConnStatus) String() string {
|
||||
switch s {
|
||||
case StatusConnecting:
|
||||
return "StatusConnecting"
|
||||
return "Connecting"
|
||||
case StatusConnected:
|
||||
return "StatusConnected"
|
||||
return "Connected"
|
||||
case StatusDisconnected:
|
||||
return "StatusDisconnected"
|
||||
return "Disconnected"
|
||||
default:
|
||||
log.Errorf("unknown status: %d", s)
|
||||
return "INVALID_PEER_CONNECTION_STATUS"
|
||||
@@ -19,7 +19,7 @@ func (s ConnStatus) String() string {
|
||||
}
|
||||
|
||||
const (
|
||||
StatusConnected = iota
|
||||
StatusConnected ConnStatus = iota
|
||||
StatusConnecting
|
||||
StatusDisconnected
|
||||
)
|
||||
|
||||
@@ -12,9 +12,9 @@ func TestConnStatus_String(t *testing.T) {
|
||||
status ConnStatus
|
||||
want string
|
||||
}{
|
||||
{"StatusConnected", StatusConnected, "StatusConnected"},
|
||||
{"StatusDisconnected", StatusDisconnected, "StatusDisconnected"},
|
||||
{"StatusConnecting", StatusConnecting, "StatusConnecting"},
|
||||
{"StatusConnected", StatusConnected, "Connected"},
|
||||
{"StatusDisconnected", StatusDisconnected, "Disconnected"},
|
||||
{"StatusConnecting", StatusConnecting, "Connecting"},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.19.4
|
||||
// protoc v3.21.2
|
||||
// source: daemon.proto
|
||||
|
||||
package proto
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
_ "google.golang.org/protobuf/types/descriptorpb"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
@@ -332,6 +333,8 @@ type StatusRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
GetFullPeerStatus bool `protobuf:"varint,1,opt,name=getFullPeerStatus,proto3" json:"getFullPeerStatus,omitempty"`
|
||||
}
|
||||
|
||||
func (x *StatusRequest) Reset() {
|
||||
@@ -366,13 +369,21 @@ func (*StatusRequest) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *StatusRequest) GetGetFullPeerStatus() bool {
|
||||
if x != nil {
|
||||
return x.GetFullPeerStatus
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type StatusResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// status of the server.
|
||||
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
|
||||
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
|
||||
FullStatus *FullStatus `protobuf:"bytes,2,opt,name=fullStatus,proto3" json:"fullStatus,omitempty"`
|
||||
}
|
||||
|
||||
func (x *StatusResponse) Reset() {
|
||||
@@ -414,6 +425,13 @@ func (x *StatusResponse) GetStatus() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StatusResponse) GetFullStatus() *FullStatus {
|
||||
if x != nil {
|
||||
return x.FullStatus
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DownRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -612,83 +630,493 @@ func (x *GetConfigResponse) GetAdminURL() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// PeerState contains the latest state of a peer
|
||||
type PeerState struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
IP string `protobuf:"bytes,1,opt,name=IP,proto3" json:"IP,omitempty"`
|
||||
PubKey string `protobuf:"bytes,2,opt,name=pubKey,proto3" json:"pubKey,omitempty"`
|
||||
ConnStatus string `protobuf:"bytes,3,opt,name=connStatus,proto3" json:"connStatus,omitempty"`
|
||||
ConnStatusUpdate *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=connStatusUpdate,proto3" json:"connStatusUpdate,omitempty"`
|
||||
Relayed bool `protobuf:"varint,5,opt,name=relayed,proto3" json:"relayed,omitempty"`
|
||||
Direct bool `protobuf:"varint,6,opt,name=direct,proto3" json:"direct,omitempty"`
|
||||
LocalIceCandidateType string `protobuf:"bytes,7,opt,name=localIceCandidateType,proto3" json:"localIceCandidateType,omitempty"`
|
||||
RemoteIceCandidateType string `protobuf:"bytes,8,opt,name=remoteIceCandidateType,proto3" json:"remoteIceCandidateType,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PeerState) Reset() {
|
||||
*x = PeerState{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_daemon_proto_msgTypes[12]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PeerState) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PeerState) ProtoMessage() {}
|
||||
|
||||
func (x *PeerState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_proto_msgTypes[12]
|
||||
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 PeerState.ProtoReflect.Descriptor instead.
|
||||
func (*PeerState) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_proto_rawDescGZIP(), []int{12}
|
||||
}
|
||||
|
||||
func (x *PeerState) GetIP() string {
|
||||
if x != nil {
|
||||
return x.IP
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PeerState) GetPubKey() string {
|
||||
if x != nil {
|
||||
return x.PubKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PeerState) GetConnStatus() string {
|
||||
if x != nil {
|
||||
return x.ConnStatus
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PeerState) GetConnStatusUpdate() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.ConnStatusUpdate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *PeerState) GetRelayed() bool {
|
||||
if x != nil {
|
||||
return x.Relayed
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *PeerState) GetDirect() bool {
|
||||
if x != nil {
|
||||
return x.Direct
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *PeerState) GetLocalIceCandidateType() string {
|
||||
if x != nil {
|
||||
return x.LocalIceCandidateType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PeerState) GetRemoteIceCandidateType() string {
|
||||
if x != nil {
|
||||
return x.RemoteIceCandidateType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// LocalPeerState contains the latest state of the local peer
|
||||
type LocalPeerState struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
IP string `protobuf:"bytes,1,opt,name=IP,proto3" json:"IP,omitempty"`
|
||||
PubKey string `protobuf:"bytes,2,opt,name=pubKey,proto3" json:"pubKey,omitempty"`
|
||||
KernelInterface bool `protobuf:"varint,3,opt,name=kernelInterface,proto3" json:"kernelInterface,omitempty"`
|
||||
}
|
||||
|
||||
func (x *LocalPeerState) Reset() {
|
||||
*x = LocalPeerState{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_daemon_proto_msgTypes[13]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *LocalPeerState) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*LocalPeerState) ProtoMessage() {}
|
||||
|
||||
func (x *LocalPeerState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_proto_msgTypes[13]
|
||||
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 LocalPeerState.ProtoReflect.Descriptor instead.
|
||||
func (*LocalPeerState) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_proto_rawDescGZIP(), []int{13}
|
||||
}
|
||||
|
||||
func (x *LocalPeerState) GetIP() string {
|
||||
if x != nil {
|
||||
return x.IP
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *LocalPeerState) GetPubKey() string {
|
||||
if x != nil {
|
||||
return x.PubKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *LocalPeerState) GetKernelInterface() bool {
|
||||
if x != nil {
|
||||
return x.KernelInterface
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SignalState contains the latest state of a signal connection
|
||||
type SignalState struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
URL string `protobuf:"bytes,1,opt,name=URL,proto3" json:"URL,omitempty"`
|
||||
Connected bool `protobuf:"varint,2,opt,name=connected,proto3" json:"connected,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SignalState) Reset() {
|
||||
*x = SignalState{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_daemon_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SignalState) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SignalState) ProtoMessage() {}
|
||||
|
||||
func (x *SignalState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_proto_msgTypes[14]
|
||||
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 SignalState.ProtoReflect.Descriptor instead.
|
||||
func (*SignalState) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
func (x *SignalState) GetURL() string {
|
||||
if x != nil {
|
||||
return x.URL
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SignalState) GetConnected() bool {
|
||||
if x != nil {
|
||||
return x.Connected
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ManagementState contains the latest state of a management connection
|
||||
type ManagementState struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
URL string `protobuf:"bytes,1,opt,name=URL,proto3" json:"URL,omitempty"`
|
||||
Connected bool `protobuf:"varint,2,opt,name=connected,proto3" json:"connected,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ManagementState) Reset() {
|
||||
*x = ManagementState{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_daemon_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ManagementState) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ManagementState) ProtoMessage() {}
|
||||
|
||||
func (x *ManagementState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_proto_msgTypes[15]
|
||||
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 ManagementState.ProtoReflect.Descriptor instead.
|
||||
func (*ManagementState) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *ManagementState) GetURL() string {
|
||||
if x != nil {
|
||||
return x.URL
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ManagementState) GetConnected() bool {
|
||||
if x != nil {
|
||||
return x.Connected
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FullStatus contains the full state held by the Status instance
|
||||
type FullStatus struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ManagementState *ManagementState `protobuf:"bytes,1,opt,name=managementState,proto3" json:"managementState,omitempty"`
|
||||
SignalState *SignalState `protobuf:"bytes,2,opt,name=signalState,proto3" json:"signalState,omitempty"`
|
||||
LocalPeerState *LocalPeerState `protobuf:"bytes,3,opt,name=localPeerState,proto3" json:"localPeerState,omitempty"`
|
||||
Peers []*PeerState `protobuf:"bytes,4,rep,name=peers,proto3" json:"peers,omitempty"`
|
||||
}
|
||||
|
||||
func (x *FullStatus) Reset() {
|
||||
*x = FullStatus{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_daemon_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *FullStatus) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*FullStatus) ProtoMessage() {}
|
||||
|
||||
func (x *FullStatus) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_proto_msgTypes[16]
|
||||
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 FullStatus.ProtoReflect.Descriptor instead.
|
||||
func (*FullStatus) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
func (x *FullStatus) GetManagementState() *ManagementState {
|
||||
if x != nil {
|
||||
return x.ManagementState
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *FullStatus) GetSignalState() *SignalState {
|
||||
if x != nil {
|
||||
return x.SignalState
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *FullStatus) GetLocalPeerState() *LocalPeerState {
|
||||
if x != nil {
|
||||
return x.LocalPeerState
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *FullStatus) GetPeers() []*PeerState {
|
||||
if x != nil {
|
||||
return x.Peers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_daemon_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_daemon_proto_rawDesc = []byte{
|
||||
0x0a, 0x0c, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06,
|
||||
0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
|
||||
0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x90, 0x01, 0x0a, 0x0c, 0x4c, 0x6f, 0x67,
|
||||
0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x74,
|
||||
0x75, 0x70, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x74,
|
||||
0x75, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x53, 0x68, 0x61, 0x72,
|
||||
0x65, 0x64, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x65,
|
||||
0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x6d, 0x61, 0x6e,
|
||||
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x55, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x55, 0x72, 0x6c, 0x12,
|
||||
0x1a, 0x0a, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x52, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x52, 0x4c, 0x22, 0xb5, 0x01, 0x0a, 0x0d,
|
||||
0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a,
|
||||
0x0d, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x53, 0x53, 0x4f, 0x4c, 0x6f,
|
||||
0x67, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12,
|
||||
0x28, 0x0a, 0x0f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55,
|
||||
0x52, 0x49, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69,
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x52, 0x49, 0x12, 0x38, 0x0a, 0x17, 0x76, 0x65, 0x72,
|
||||
0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
|
||||
0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x90, 0x01, 0x0a, 0x0c, 0x4c, 0x6f,
|
||||
0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65,
|
||||
0x74, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65,
|
||||
0x74, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x53, 0x68, 0x61,
|
||||
0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72,
|
||||
0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x6d, 0x61,
|
||||
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x55, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x55, 0x72, 0x6c,
|
||||
0x12, 0x1a, 0x0a, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x52, 0x4c, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x52, 0x4c, 0x22, 0xb5, 0x01, 0x0a,
|
||||
0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24,
|
||||
0x0a, 0x0d, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x53, 0x53, 0x4f, 0x4c,
|
||||
0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65,
|
||||
0x12, 0x28, 0x0a, 0x0f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x55, 0x52, 0x49, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x76, 0x65, 0x72, 0x69, 0x66,
|
||||
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x52, 0x49, 0x12, 0x38, 0x0a, 0x17, 0x76, 0x65,
|
||||
0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x52, 0x49, 0x43, 0x6f, 0x6d,
|
||||
0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x76, 0x65, 0x72,
|
||||
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x52, 0x49, 0x43, 0x6f, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x76, 0x65, 0x72, 0x69,
|
||||
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x52, 0x49, 0x43, 0x6f, 0x6d, 0x70, 0x6c,
|
||||
0x65, 0x74, 0x65, 0x22, 0x31, 0x0a, 0x13, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f,
|
||||
0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73,
|
||||
0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73,
|
||||
0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53,
|
||||
0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0b,
|
||||
0x0a, 0x09, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x0c, 0x0a, 0x0a, 0x55,
|
||||
0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x28, 0x0a, 0x0e, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x22, 0x0d, 0x0a, 0x0b, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x22, 0x0e, 0x0a, 0x0c, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb3, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a,
|
||||
0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x55, 0x72, 0x6c, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||
0x55, 0x72, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x69, 0x6c,
|
||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46,
|
||||
0x69, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x6f, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x22, 0x0a,
|
||||
0x0c, 0x70, 0x72, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65,
|
||||
0x79, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x52, 0x4c, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x52, 0x4c, 0x32, 0xf7, 0x02,
|
||||
0x0a, 0x0d, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x36, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x14, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f,
|
||||
0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15,
|
||||
0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0c, 0x57, 0x61, 0x69, 0x74, 0x53,
|
||||
0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61,
|
||||
0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x02, 0x55, 0x70, 0x12, 0x11, 0x2e, 0x64, 0x61, 0x65,
|
||||
0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e,
|
||||
0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x15, 0x2e,
|
||||
0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33,
|
||||
0x0a, 0x04, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x13, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e,
|
||||
0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x64, 0x61,
|
||||
0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x12, 0x18, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x64, 0x61, 0x65,
|
||||
0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6c, 0x65, 0x74, 0x65, 0x22, 0x31, 0x0a, 0x13, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c,
|
||||
0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75,
|
||||
0x73, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75,
|
||||
0x73, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x57, 0x61, 0x69, 0x74, 0x53,
|
||||
0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x0b, 0x0a, 0x09, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x0c, 0x0a, 0x0a,
|
||||
0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3d, 0x0a, 0x0d, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x11, 0x67,
|
||||
0x65, 0x74, 0x46, 0x75, 0x6c, 0x6c, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x67, 0x65, 0x74, 0x46, 0x75, 0x6c, 0x6c, 0x50,
|
||||
0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x5c, 0x0a, 0x0e, 0x53, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x12, 0x32, 0x0a, 0x0a, 0x66, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0a, 0x66, 0x75, 0x6c,
|
||||
0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x0d, 0x0a, 0x0b, 0x44, 0x6f, 0x77, 0x6e, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x0e, 0x0a, 0x0c, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb3, 0x01, 0x0a, 0x11, 0x47,
|
||||
0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x24, 0x0a, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x55, 0x72,
|
||||
0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d,
|
||||
0x65, 0x6e, 0x74, 0x55, 0x72, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x46, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x6f, 0x67, 0x46, 0x69, 0x6c,
|
||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x46, 0x69, 0x6c, 0x65,
|
||||
0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65,
|
||||
0x64, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x52, 0x4c,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x52, 0x4c,
|
||||
0x22, 0xbb, 0x02, 0x0a, 0x09, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e,
|
||||
0x0a, 0x02, 0x49, 0x50, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x50, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x63, 0x6f,
|
||||
0x6e, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x07, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x72, 0x65,
|
||||
0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
|
||||
0x12, 0x34, 0x0a, 0x15, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x64,
|
||||
0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x15, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61,
|
||||
0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x16, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
|
||||
0x49, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65,
|
||||
0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x63,
|
||||
0x65, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x62,
|
||||
0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65,
|
||||
0x12, 0x0e, 0x0a, 0x02, 0x49, 0x50, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x50,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x6b, 0x65, 0x72, 0x6e,
|
||||
0x65, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x0f, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61,
|
||||
0x63, 0x65, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74,
|
||||
0x65, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
||||
0x55, 0x52, 0x4c, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65,
|
||||
0x64, 0x22, 0x41, 0x0a, 0x0f, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53,
|
||||
0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x03, 0x55, 0x52, 0x4c, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
|
||||
0x63, 0x74, 0x65, 0x64, 0x22, 0xef, 0x01, 0x0a, 0x0a, 0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x12, 0x41, 0x0a, 0x0f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e,
|
||||
0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x64,
|
||||
0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||
0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e,
|
||||
0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c,
|
||||
0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x61,
|
||||
0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65,
|
||||
0x52, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3e, 0x0a,
|
||||
0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c,
|
||||
0x6f, 0x63, 0x61, 0x6c, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0e, 0x6c,
|
||||
0x6f, 0x63, 0x61, 0x6c, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a,
|
||||
0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64,
|
||||
0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52,
|
||||
0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x32, 0xf7, 0x02, 0x0a, 0x0d, 0x44, 0x61, 0x65, 0x6d, 0x6f,
|
||||
0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69,
|
||||
0x6e, 0x12, 0x14, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x12, 0x4b, 0x0a, 0x0c, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
|
||||
0x12, 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53,
|
||||
0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e,
|
||||
0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f,
|
||||
0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a,
|
||||
0x02, 0x55, 0x70, 0x12, 0x11, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e,
|
||||
0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x06,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x15, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e,
|
||||
0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x04, 0x44, 0x6f, 0x77, 0x6e, 0x12,
|
||||
0x13, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x6f,
|
||||
0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x09,
|
||||
0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x2e, 0x64, 0x61, 0x65, 0x6d,
|
||||
0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -703,39 +1131,51 @@ func file_daemon_proto_rawDescGZIP() []byte {
|
||||
return file_daemon_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
|
||||
var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
|
||||
var file_daemon_proto_goTypes = []interface{}{
|
||||
(*LoginRequest)(nil), // 0: daemon.LoginRequest
|
||||
(*LoginResponse)(nil), // 1: daemon.LoginResponse
|
||||
(*WaitSSOLoginRequest)(nil), // 2: daemon.WaitSSOLoginRequest
|
||||
(*WaitSSOLoginResponse)(nil), // 3: daemon.WaitSSOLoginResponse
|
||||
(*UpRequest)(nil), // 4: daemon.UpRequest
|
||||
(*UpResponse)(nil), // 5: daemon.UpResponse
|
||||
(*StatusRequest)(nil), // 6: daemon.StatusRequest
|
||||
(*StatusResponse)(nil), // 7: daemon.StatusResponse
|
||||
(*DownRequest)(nil), // 8: daemon.DownRequest
|
||||
(*DownResponse)(nil), // 9: daemon.DownResponse
|
||||
(*GetConfigRequest)(nil), // 10: daemon.GetConfigRequest
|
||||
(*GetConfigResponse)(nil), // 11: daemon.GetConfigResponse
|
||||
(*LoginRequest)(nil), // 0: daemon.LoginRequest
|
||||
(*LoginResponse)(nil), // 1: daemon.LoginResponse
|
||||
(*WaitSSOLoginRequest)(nil), // 2: daemon.WaitSSOLoginRequest
|
||||
(*WaitSSOLoginResponse)(nil), // 3: daemon.WaitSSOLoginResponse
|
||||
(*UpRequest)(nil), // 4: daemon.UpRequest
|
||||
(*UpResponse)(nil), // 5: daemon.UpResponse
|
||||
(*StatusRequest)(nil), // 6: daemon.StatusRequest
|
||||
(*StatusResponse)(nil), // 7: daemon.StatusResponse
|
||||
(*DownRequest)(nil), // 8: daemon.DownRequest
|
||||
(*DownResponse)(nil), // 9: daemon.DownResponse
|
||||
(*GetConfigRequest)(nil), // 10: daemon.GetConfigRequest
|
||||
(*GetConfigResponse)(nil), // 11: daemon.GetConfigResponse
|
||||
(*PeerState)(nil), // 12: daemon.PeerState
|
||||
(*LocalPeerState)(nil), // 13: daemon.LocalPeerState
|
||||
(*SignalState)(nil), // 14: daemon.SignalState
|
||||
(*ManagementState)(nil), // 15: daemon.ManagementState
|
||||
(*FullStatus)(nil), // 16: daemon.FullStatus
|
||||
(*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp
|
||||
}
|
||||
var file_daemon_proto_depIdxs = []int32{
|
||||
0, // 0: daemon.DaemonService.Login:input_type -> daemon.LoginRequest
|
||||
2, // 1: daemon.DaemonService.WaitSSOLogin:input_type -> daemon.WaitSSOLoginRequest
|
||||
4, // 2: daemon.DaemonService.Up:input_type -> daemon.UpRequest
|
||||
6, // 3: daemon.DaemonService.Status:input_type -> daemon.StatusRequest
|
||||
8, // 4: daemon.DaemonService.Down:input_type -> daemon.DownRequest
|
||||
10, // 5: daemon.DaemonService.GetConfig:input_type -> daemon.GetConfigRequest
|
||||
1, // 6: daemon.DaemonService.Login:output_type -> daemon.LoginResponse
|
||||
3, // 7: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse
|
||||
5, // 8: daemon.DaemonService.Up:output_type -> daemon.UpResponse
|
||||
7, // 9: daemon.DaemonService.Status:output_type -> daemon.StatusResponse
|
||||
9, // 10: daemon.DaemonService.Down:output_type -> daemon.DownResponse
|
||||
11, // 11: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse
|
||||
6, // [6:12] is the sub-list for method output_type
|
||||
0, // [0:6] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
16, // 0: daemon.StatusResponse.fullStatus:type_name -> daemon.FullStatus
|
||||
17, // 1: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp
|
||||
15, // 2: daemon.FullStatus.managementState:type_name -> daemon.ManagementState
|
||||
14, // 3: daemon.FullStatus.signalState:type_name -> daemon.SignalState
|
||||
13, // 4: daemon.FullStatus.localPeerState:type_name -> daemon.LocalPeerState
|
||||
12, // 5: daemon.FullStatus.peers:type_name -> daemon.PeerState
|
||||
0, // 6: daemon.DaemonService.Login:input_type -> daemon.LoginRequest
|
||||
2, // 7: daemon.DaemonService.WaitSSOLogin:input_type -> daemon.WaitSSOLoginRequest
|
||||
4, // 8: daemon.DaemonService.Up:input_type -> daemon.UpRequest
|
||||
6, // 9: daemon.DaemonService.Status:input_type -> daemon.StatusRequest
|
||||
8, // 10: daemon.DaemonService.Down:input_type -> daemon.DownRequest
|
||||
10, // 11: daemon.DaemonService.GetConfig:input_type -> daemon.GetConfigRequest
|
||||
1, // 12: daemon.DaemonService.Login:output_type -> daemon.LoginResponse
|
||||
3, // 13: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse
|
||||
5, // 14: daemon.DaemonService.Up:output_type -> daemon.UpResponse
|
||||
7, // 15: daemon.DaemonService.Status:output_type -> daemon.StatusResponse
|
||||
9, // 16: daemon.DaemonService.Down:output_type -> daemon.DownResponse
|
||||
11, // 17: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse
|
||||
12, // [12:18] is the sub-list for method output_type
|
||||
6, // [6:12] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_daemon_proto_init() }
|
||||
@@ -888,6 +1328,66 @@ func file_daemon_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_daemon_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PeerState); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_daemon_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*LocalPeerState); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_daemon_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SignalState); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_daemon_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ManagementState); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_daemon_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*FullStatus); 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{
|
||||
@@ -895,7 +1395,7 @@ func file_daemon_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_daemon_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 12,
|
||||
NumMessages: 17,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
option go_package = "/proto";
|
||||
|
||||
@@ -59,11 +60,14 @@ message UpRequest {}
|
||||
|
||||
message UpResponse {}
|
||||
|
||||
message StatusRequest{}
|
||||
message StatusRequest{
|
||||
bool getFullPeerStatus = 1;
|
||||
}
|
||||
|
||||
message StatusResponse{
|
||||
// status of the server.
|
||||
string status = 1;
|
||||
FullStatus fullStatus = 2;
|
||||
}
|
||||
|
||||
message DownRequest {}
|
||||
@@ -88,3 +92,41 @@ message GetConfigResponse {
|
||||
// adminURL settings value.
|
||||
string adminURL = 5;
|
||||
}
|
||||
|
||||
// PeerState contains the latest state of a peer
|
||||
message PeerState {
|
||||
string IP = 1;
|
||||
string pubKey = 2;
|
||||
string connStatus = 3;
|
||||
google.protobuf.Timestamp connStatusUpdate = 4;
|
||||
bool relayed = 5;
|
||||
bool direct = 6;
|
||||
string localIceCandidateType = 7;
|
||||
string remoteIceCandidateType =8;
|
||||
}
|
||||
|
||||
// LocalPeerState contains the latest state of the local peer
|
||||
message LocalPeerState {
|
||||
string IP = 1;
|
||||
string pubKey = 2;
|
||||
bool kernelInterface =3;
|
||||
}
|
||||
|
||||
// SignalState contains the latest state of a signal connection
|
||||
message SignalState {
|
||||
string URL = 1;
|
||||
bool connected = 2;
|
||||
}
|
||||
|
||||
// ManagementState contains the latest state of a management connection
|
||||
message ManagementState {
|
||||
string URL = 1;
|
||||
bool connected = 2;
|
||||
}
|
||||
// FullStatus contains the full state held by the Status instance
|
||||
message FullStatus {
|
||||
ManagementState managementState = 1;
|
||||
SignalState signalState = 2;
|
||||
LocalPeerState localPeerState = 3;
|
||||
repeated PeerState peers = 4;
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
nbStatus "github.com/netbirdio/netbird/client/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -31,6 +33,8 @@ type Server struct {
|
||||
mutex sync.Mutex
|
||||
config *internal.Config
|
||||
proto.UnimplementedDaemonServiceServer
|
||||
|
||||
statusRecorder *nbStatus.Status
|
||||
}
|
||||
|
||||
type oauthAuthFlow struct {
|
||||
@@ -52,6 +56,8 @@ func New(ctx context.Context, managementURL, adminURL, configPath, logFile strin
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
state := internal.CtxGetState(s.rootCtx)
|
||||
|
||||
// if current state contains any error, return it
|
||||
@@ -86,11 +92,16 @@ func (s *Server) Start() error {
|
||||
}
|
||||
|
||||
// if configuration exists, we just start connections.
|
||||
config, _ = internal.UpdateOldManagementPort(ctx, config, s.configPath)
|
||||
|
||||
s.config = config
|
||||
|
||||
if s.statusRecorder == nil {
|
||||
s.statusRecorder = nbStatus.NewRecorder()
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := internal.RunClient(ctx, config); err != nil {
|
||||
if err := internal.RunClient(ctx, config, s.statusRecorder); err != nil {
|
||||
log.Errorf("init connections: %v", err)
|
||||
}
|
||||
}()
|
||||
@@ -158,6 +169,12 @@ func (s *Server) Login(callerCtx context.Context, msg *proto.LoginRequest) (*pro
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if msg.ManagementUrl == "" {
|
||||
config, _ = internal.UpdateOldManagementPort(ctx, config, s.configPath)
|
||||
s.config = config
|
||||
s.managementURL = config.ManagementURL.String()
|
||||
}
|
||||
|
||||
s.mutex.Lock()
|
||||
s.config = config
|
||||
s.mutex.Unlock()
|
||||
@@ -350,8 +367,12 @@ func (s *Server) Up(callerCtx context.Context, msg *proto.UpRequest) (*proto.UpR
|
||||
return nil, fmt.Errorf("config is not defined, please call login command first")
|
||||
}
|
||||
|
||||
if s.statusRecorder == nil {
|
||||
s.statusRecorder = nbStatus.NewRecorder()
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := internal.RunClient(ctx, s.config); err != nil {
|
||||
if err := internal.RunClient(ctx, s.config, s.statusRecorder); err != nil {
|
||||
log.Errorf("run client connection: %v", state.Wrap(err))
|
||||
return
|
||||
}
|
||||
@@ -375,7 +396,7 @@ func (s *Server) Down(ctx context.Context, msg *proto.DownRequest) (*proto.DownR
|
||||
|
||||
// Status starts engine work in the daemon.
|
||||
func (s *Server) Status(
|
||||
ctx context.Context,
|
||||
_ context.Context,
|
||||
msg *proto.StatusRequest,
|
||||
) (*proto.StatusResponse, error) {
|
||||
s.mutex.Lock()
|
||||
@@ -386,7 +407,19 @@ func (s *Server) Status(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &proto.StatusResponse{Status: string(status)}, nil
|
||||
statusResponse := proto.StatusResponse{Status: string(status)}
|
||||
|
||||
if s.statusRecorder == nil {
|
||||
s.statusRecorder = nbStatus.NewRecorder()
|
||||
}
|
||||
|
||||
if msg.GetFullPeerStatus {
|
||||
fullStatus := s.statusRecorder.GetFullStatus()
|
||||
pbFullStatus := toProtoFullStatus(fullStatus)
|
||||
statusResponse.FullStatus = pbFullStatus
|
||||
}
|
||||
|
||||
return &statusResponse, nil
|
||||
}
|
||||
|
||||
// GetConfig of the daemon.
|
||||
@@ -422,3 +455,37 @@ func (s *Server) GetConfig(ctx context.Context, msg *proto.GetConfigRequest) (*p
|
||||
PreSharedKey: preSharedKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toProtoFullStatus(fullStatus nbStatus.FullStatus) *proto.FullStatus {
|
||||
pbFullStatus := proto.FullStatus{
|
||||
ManagementState: &proto.ManagementState{},
|
||||
SignalState: &proto.SignalState{},
|
||||
LocalPeerState: &proto.LocalPeerState{},
|
||||
Peers: []*proto.PeerState{},
|
||||
}
|
||||
|
||||
pbFullStatus.ManagementState.URL = fullStatus.ManagementState.URL
|
||||
pbFullStatus.ManagementState.Connected = fullStatus.ManagementState.Connected
|
||||
|
||||
pbFullStatus.SignalState.URL = fullStatus.SignalState.URL
|
||||
pbFullStatus.SignalState.Connected = fullStatus.SignalState.Connected
|
||||
|
||||
pbFullStatus.LocalPeerState.IP = fullStatus.LocalPeerState.IP
|
||||
pbFullStatus.LocalPeerState.PubKey = fullStatus.LocalPeerState.PubKey
|
||||
pbFullStatus.LocalPeerState.KernelInterface = fullStatus.LocalPeerState.KernelInterface
|
||||
|
||||
for _, peerState := range fullStatus.Peers {
|
||||
pbPeerState := &proto.PeerState{
|
||||
IP: peerState.IP,
|
||||
PubKey: peerState.PubKey,
|
||||
ConnStatus: peerState.ConnStatus,
|
||||
ConnStatusUpdate: timestamppb.New(peerState.ConnStatusUpdate),
|
||||
Relayed: peerState.Relayed,
|
||||
Direct: peerState.Direct,
|
||||
LocalIceCandidateType: peerState.LocalIceCandidateType,
|
||||
RemoteIceCandidateType: peerState.RemoteIceCandidateType,
|
||||
}
|
||||
pbFullStatus.Peers = append(pbFullStatus.Peers, pbPeerState)
|
||||
}
|
||||
return &pbFullStatus
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"golang.org/x/term"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Client wraps crypto/ssh Client to simplify usage
|
||||
@@ -92,7 +93,8 @@ func DialWithKey(addr, user string, privateKey []byte) (*Client, error) {
|
||||
}
|
||||
|
||||
config := &ssh.ClientConfig{
|
||||
User: user,
|
||||
User: user,
|
||||
Timeout: 5 * time.Second,
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.PublicKeys(signer),
|
||||
},
|
||||
|
||||
36
client/ssh/login.go
Normal file
36
client/ssh/login.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/netbirdio/netbird/util"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func getLoginCmd(user string, remoteAddr net.Addr) (loginPath string, args []string, err error) {
|
||||
loginPath, err = exec.LookPath("login")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
addrPort, err := netip.ParseAddrPort(remoteAddr.String())
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
|
||||
if util.FileExists("/etc/arch-release") && !util.FileExists("/etc/pam.d/remote") {
|
||||
// detect if Arch Linux
|
||||
return loginPath, []string{"-f", user, "-p"}, nil
|
||||
}
|
||||
|
||||
return loginPath, []string{"-f", user, "-h", addrPort.Addr().String(), "-p"}, nil
|
||||
} else if runtime.GOOS == "darwin" {
|
||||
return loginPath, []string{"-fp", "-h", addrPort.Addr().String(), user}, nil
|
||||
}
|
||||
|
||||
return "", nil, fmt.Errorf("unsupported platform")
|
||||
}
|
||||
10
client/ssh/lookup.go
Normal file
10
client/ssh/lookup.go
Normal file
@@ -0,0 +1,10 @@
|
||||
//go:build !darwin
|
||||
// +build !darwin
|
||||
|
||||
package ssh
|
||||
|
||||
import "os/user"
|
||||
|
||||
func userNameLookup(username string) (*user.User, error) {
|
||||
return user.Lookup(username)
|
||||
}
|
||||
47
client/ssh/lookup_darwin.go
Normal file
47
client/ssh/lookup_darwin.go
Normal file
@@ -0,0 +1,47 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func userNameLookup(username string) (*user.User, error) {
|
||||
var userObject *user.User
|
||||
userObject, err := user.Lookup(username)
|
||||
if err != nil && err.Error() == user.UnknownUserError(username).Error() {
|
||||
return idUserNameLookup(username)
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return userObject, nil
|
||||
}
|
||||
|
||||
func idUserNameLookup(username string) (*user.User, error) {
|
||||
cmd := exec.Command("id", "-P", username)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while retrieving user with id -P command, error: %v", err)
|
||||
}
|
||||
colon := ":"
|
||||
|
||||
if !bytes.Contains(out, []byte(username+colon)) {
|
||||
return nil, fmt.Errorf("unable to find user in returned string")
|
||||
}
|
||||
// netbird:********:501:20::0:0:netbird:/Users/netbird:/bin/zsh
|
||||
parts := strings.SplitN(string(out), colon, 10)
|
||||
userObject := &user.User{
|
||||
Username: parts[0],
|
||||
Uid: parts[2],
|
||||
Gid: parts[3],
|
||||
Name: parts[7],
|
||||
HomeDir: parts[8],
|
||||
}
|
||||
return userObject, nil
|
||||
}
|
||||
@@ -9,6 +9,9 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -105,12 +108,20 @@ func (srv *DefaultServer) publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) b
|
||||
return false
|
||||
}
|
||||
|
||||
func getShellType() string {
|
||||
shell := os.Getenv("SHELL")
|
||||
if shell == "" {
|
||||
shell = "sh"
|
||||
func prepareUserEnv(user *user.User, shell string) []string {
|
||||
return []string{
|
||||
fmt.Sprintf("SHELL=" + shell),
|
||||
fmt.Sprintf("USER=" + user.Username),
|
||||
fmt.Sprintf("HOME=" + user.HomeDir),
|
||||
}
|
||||
return shell
|
||||
}
|
||||
|
||||
func acceptEnv(s string) bool {
|
||||
split := strings.Split(s, "=")
|
||||
if len(split) != 2 {
|
||||
return false
|
||||
}
|
||||
return split[0] == "TERM" || split[0] == "LANG" || strings.HasPrefix(split[0], "LC_")
|
||||
}
|
||||
|
||||
// sessionHandler handles SSH session post auth
|
||||
@@ -118,14 +129,54 @@ func (srv *DefaultServer) sessionHandler(session ssh.Session) {
|
||||
srv.mu.Lock()
|
||||
srv.sessions = append(srv.sessions, session)
|
||||
srv.mu.Unlock()
|
||||
|
||||
defer func() {
|
||||
err := session.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
localUser, err := userNameLookup(session.User())
|
||||
if err != nil {
|
||||
_, err = fmt.Fprintf(session, "remote SSH server couldn't find local user %s\n", session.User()) //nolint
|
||||
err = session.Exit(1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Warnf("failed SSH session from %v, user %s", session.RemoteAddr(), session.User())
|
||||
return
|
||||
}
|
||||
|
||||
ptyReq, winCh, isPty := session.Pty()
|
||||
if isPty {
|
||||
cmd := exec.Command(getShellType())
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%session", ptyReq.Term))
|
||||
loginCmd, loginArgs, err := getLoginCmd(localUser.Username, session.RemoteAddr())
|
||||
if err != nil {
|
||||
log.Warnf("failed logging-in user %s from remote IP %s", localUser.Username, session.RemoteAddr().String())
|
||||
return
|
||||
}
|
||||
cmd := exec.Command(loginCmd, loginArgs...)
|
||||
go func() {
|
||||
<-session.Context().Done()
|
||||
err := cmd.Process.Kill()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
cmd.Dir = localUser.HomeDir
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", ptyReq.Term))
|
||||
cmd.Env = append(cmd.Env, prepareUserEnv(localUser, getUserShell(localUser.Uid))...)
|
||||
for _, v := range session.Environ() {
|
||||
if acceptEnv(v) {
|
||||
cmd.Env = append(cmd.Env, v)
|
||||
}
|
||||
}
|
||||
|
||||
file, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
log.Errorf("failed starting SSH server %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for win := range winCh {
|
||||
setWinSize(file, win.Width, win.Height)
|
||||
@@ -181,3 +232,19 @@ func (srv *DefaultServer) Start() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getUserShell(userID string) string {
|
||||
if runtime.GOOS == "linux" {
|
||||
output, _ := exec.Command("getent", "passwd", userID).Output()
|
||||
line := strings.SplitN(string(output), ":", 10)
|
||||
if len(line) > 6 {
|
||||
return strings.TrimSpace(line[6])
|
||||
}
|
||||
}
|
||||
|
||||
shell := os.Getenv("SHELL")
|
||||
if shell == "" {
|
||||
shell = "/bin/sh"
|
||||
}
|
||||
return shell
|
||||
}
|
||||
|
||||
191
client/status/status.go
Normal file
191
client/status/status.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package status
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PeerState contains the latest state of a peer
|
||||
type PeerState struct {
|
||||
IP string
|
||||
PubKey string
|
||||
ConnStatus string
|
||||
ConnStatusUpdate time.Time
|
||||
Relayed bool
|
||||
Direct bool
|
||||
LocalIceCandidateType string
|
||||
RemoteIceCandidateType string
|
||||
}
|
||||
|
||||
// LocalPeerState contains the latest state of the local peer
|
||||
type LocalPeerState struct {
|
||||
IP string
|
||||
PubKey string
|
||||
KernelInterface bool
|
||||
}
|
||||
|
||||
// SignalState contains the latest state of a signal connection
|
||||
type SignalState struct {
|
||||
URL string
|
||||
Connected bool
|
||||
}
|
||||
|
||||
// ManagementState contains the latest state of a management connection
|
||||
type ManagementState struct {
|
||||
URL string
|
||||
Connected bool
|
||||
}
|
||||
|
||||
// FullStatus contains the full state held by the Status instance
|
||||
type FullStatus struct {
|
||||
Peers []PeerState
|
||||
ManagementState ManagementState
|
||||
SignalState SignalState
|
||||
LocalPeerState LocalPeerState
|
||||
}
|
||||
|
||||
// Status holds a state of peers, signal and management connections
|
||||
type Status struct {
|
||||
mux sync.Mutex
|
||||
peers map[string]PeerState
|
||||
signal SignalState
|
||||
management ManagementState
|
||||
localPeer LocalPeerState
|
||||
}
|
||||
|
||||
// NewRecorder returns a new Status instance
|
||||
func NewRecorder() *Status {
|
||||
return &Status{
|
||||
peers: make(map[string]PeerState),
|
||||
}
|
||||
}
|
||||
|
||||
// AddPeer adds peer to Daemon status map
|
||||
func (d *Status) AddPeer(peerPubKey string) error {
|
||||
d.mux.Lock()
|
||||
defer d.mux.Unlock()
|
||||
|
||||
_, ok := d.peers[peerPubKey]
|
||||
if ok {
|
||||
return errors.New("peer already exist")
|
||||
}
|
||||
d.peers[peerPubKey] = PeerState{PubKey: peerPubKey}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemovePeer removes peer from Daemon status map
|
||||
func (d *Status) RemovePeer(peerPubKey string) error {
|
||||
d.mux.Lock()
|
||||
defer d.mux.Unlock()
|
||||
|
||||
_, ok := d.peers[peerPubKey]
|
||||
if ok {
|
||||
delete(d.peers, peerPubKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("no peer with to remove")
|
||||
}
|
||||
|
||||
// UpdatePeerState updates peer status
|
||||
func (d *Status) UpdatePeerState(receivedState PeerState) error {
|
||||
d.mux.Lock()
|
||||
defer d.mux.Unlock()
|
||||
|
||||
peerState, ok := d.peers[receivedState.PubKey]
|
||||
if !ok {
|
||||
return errors.New("peer doesn't exist")
|
||||
}
|
||||
|
||||
if receivedState.IP != "" {
|
||||
peerState.IP = receivedState.IP
|
||||
}
|
||||
|
||||
if receivedState.ConnStatus != peerState.ConnStatus {
|
||||
peerState.ConnStatus = receivedState.ConnStatus
|
||||
peerState.ConnStatusUpdate = receivedState.ConnStatusUpdate
|
||||
peerState.Direct = receivedState.Direct
|
||||
peerState.Relayed = receivedState.Relayed
|
||||
peerState.LocalIceCandidateType = receivedState.LocalIceCandidateType
|
||||
peerState.RemoteIceCandidateType = receivedState.RemoteIceCandidateType
|
||||
}
|
||||
|
||||
d.peers[receivedState.PubKey] = peerState
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateLocalPeerState updates local peer status
|
||||
func (d *Status) UpdateLocalPeerState(localPeerState LocalPeerState) {
|
||||
d.mux.Lock()
|
||||
defer d.mux.Unlock()
|
||||
|
||||
d.localPeer = localPeerState
|
||||
}
|
||||
|
||||
// CleanLocalPeerState cleans local peer status
|
||||
func (d *Status) CleanLocalPeerState() {
|
||||
d.mux.Lock()
|
||||
defer d.mux.Unlock()
|
||||
|
||||
d.localPeer = LocalPeerState{}
|
||||
}
|
||||
|
||||
// MarkManagementDisconnected sets ManagementState to disconnected
|
||||
func (d *Status) MarkManagementDisconnected(managementURL string) {
|
||||
d.mux.Lock()
|
||||
defer d.mux.Unlock()
|
||||
d.management = ManagementState{
|
||||
URL: managementURL,
|
||||
Connected: false,
|
||||
}
|
||||
}
|
||||
|
||||
// MarkManagementConnected sets ManagementState to connected
|
||||
func (d *Status) MarkManagementConnected(managementURL string) {
|
||||
d.mux.Lock()
|
||||
defer d.mux.Unlock()
|
||||
d.management = ManagementState{
|
||||
URL: managementURL,
|
||||
Connected: true,
|
||||
}
|
||||
}
|
||||
|
||||
// MarkSignalDisconnected sets SignalState to disconnected
|
||||
func (d *Status) MarkSignalDisconnected(signalURL string) {
|
||||
d.mux.Lock()
|
||||
defer d.mux.Unlock()
|
||||
d.signal = SignalState{
|
||||
signalURL,
|
||||
false,
|
||||
}
|
||||
}
|
||||
|
||||
// MarkSignalConnected sets SignalState to connected
|
||||
func (d *Status) MarkSignalConnected(signalURL string) {
|
||||
d.mux.Lock()
|
||||
defer d.mux.Unlock()
|
||||
d.signal = SignalState{
|
||||
signalURL,
|
||||
true,
|
||||
}
|
||||
}
|
||||
|
||||
// GetFullStatus gets full status
|
||||
func (d *Status) GetFullStatus() FullStatus {
|
||||
d.mux.Lock()
|
||||
defer d.mux.Unlock()
|
||||
|
||||
fullStatus := FullStatus{
|
||||
ManagementState: d.management,
|
||||
SignalState: d.signal,
|
||||
LocalPeerState: d.localPeer,
|
||||
}
|
||||
|
||||
for _, status := range d.peers {
|
||||
fullStatus.Peers = append(fullStatus.Peers, status)
|
||||
}
|
||||
|
||||
return fullStatus
|
||||
}
|
||||
185
client/status/status_test.go
Normal file
185
client/status/status_test.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package status
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAddPeer(t *testing.T) {
|
||||
key := "abc"
|
||||
status := NewRecorder()
|
||||
err := status.AddPeer(key)
|
||||
assert.NoError(t, err, "shouldn't return error")
|
||||
|
||||
_, exists := status.peers[key]
|
||||
assert.True(t, exists, "value was found")
|
||||
|
||||
err = status.AddPeer(key)
|
||||
|
||||
assert.Error(t, err, "should return error on duplicate")
|
||||
}
|
||||
|
||||
func TestUpdatePeerState(t *testing.T) {
|
||||
key := "abc"
|
||||
ip := "10.10.10.10"
|
||||
status := NewRecorder()
|
||||
peerState := PeerState{
|
||||
PubKey: key,
|
||||
}
|
||||
|
||||
status.peers[key] = peerState
|
||||
|
||||
peerState.IP = ip
|
||||
|
||||
err := status.UpdatePeerState(peerState)
|
||||
assert.NoError(t, err, "shouldn't return error")
|
||||
|
||||
state, exists := status.peers[key]
|
||||
assert.True(t, exists, "state should be found")
|
||||
assert.Equal(t, ip, state.IP, "ip should be equal")
|
||||
}
|
||||
|
||||
func TestRemovePeer(t *testing.T) {
|
||||
key := "abc"
|
||||
status := NewRecorder()
|
||||
peerState := PeerState{
|
||||
PubKey: key,
|
||||
}
|
||||
|
||||
status.peers[key] = peerState
|
||||
|
||||
err := status.RemovePeer(key)
|
||||
assert.NoError(t, err, "shouldn't return error")
|
||||
|
||||
_, exists := status.peers[key]
|
||||
assert.False(t, exists, "state value shouldn't be found")
|
||||
|
||||
err = status.RemovePeer("not existing")
|
||||
assert.Error(t, err, "should return error when peer doesn't exist")
|
||||
}
|
||||
|
||||
func TestUpdateLocalPeerState(t *testing.T) {
|
||||
localPeerState := LocalPeerState{
|
||||
IP: "10.10.10.10",
|
||||
PubKey: "abc",
|
||||
KernelInterface: false,
|
||||
}
|
||||
status := NewRecorder()
|
||||
|
||||
status.UpdateLocalPeerState(localPeerState)
|
||||
|
||||
assert.Equal(t, localPeerState, status.localPeer, "local peer status should be equal")
|
||||
}
|
||||
|
||||
func TestCleanLocalPeerState(t *testing.T) {
|
||||
emptyLocalPeerState := LocalPeerState{}
|
||||
localPeerState := LocalPeerState{
|
||||
IP: "10.10.10.10",
|
||||
PubKey: "abc",
|
||||
KernelInterface: false,
|
||||
}
|
||||
status := NewRecorder()
|
||||
|
||||
status.localPeer = localPeerState
|
||||
|
||||
status.CleanLocalPeerState()
|
||||
|
||||
assert.Equal(t, emptyLocalPeerState, status.localPeer, "local peer status should be empty")
|
||||
}
|
||||
|
||||
func TestUpdateSignalState(t *testing.T) {
|
||||
url := "https://signal"
|
||||
var tests = []struct {
|
||||
name string
|
||||
connected bool
|
||||
want SignalState
|
||||
}{
|
||||
{"should mark as connected", true, SignalState{
|
||||
|
||||
URL: url,
|
||||
Connected: true,
|
||||
}},
|
||||
{"should mark as disconnected", false, SignalState{
|
||||
URL: url,
|
||||
Connected: false,
|
||||
}},
|
||||
}
|
||||
|
||||
status := NewRecorder()
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if test.connected {
|
||||
status.MarkSignalConnected(url)
|
||||
} else {
|
||||
status.MarkSignalDisconnected(url)
|
||||
}
|
||||
assert.Equal(t, test.want, status.signal, "signal status should be equal")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateManagementState(t *testing.T) {
|
||||
url := "https://management"
|
||||
var tests = []struct {
|
||||
name string
|
||||
connected bool
|
||||
want ManagementState
|
||||
}{
|
||||
{"should mark as connected", true, ManagementState{
|
||||
|
||||
URL: url,
|
||||
Connected: true,
|
||||
}},
|
||||
{"should mark as disconnected", false, ManagementState{
|
||||
URL: url,
|
||||
Connected: false,
|
||||
}},
|
||||
}
|
||||
|
||||
status := NewRecorder()
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if test.connected {
|
||||
status.MarkManagementConnected(url)
|
||||
} else {
|
||||
status.MarkManagementDisconnected(url)
|
||||
}
|
||||
assert.Equal(t, test.want, status.management, "signal status should be equal")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFullStatus(t *testing.T) {
|
||||
key1 := "abc"
|
||||
key2 := "def"
|
||||
managementState := ManagementState{
|
||||
URL: "https://signal",
|
||||
Connected: true,
|
||||
}
|
||||
signalState := SignalState{
|
||||
URL: "https://signal",
|
||||
Connected: true,
|
||||
}
|
||||
peerState1 := PeerState{
|
||||
PubKey: key1,
|
||||
}
|
||||
|
||||
peerState2 := PeerState{
|
||||
PubKey: key2,
|
||||
}
|
||||
|
||||
status := NewRecorder()
|
||||
|
||||
status.management = managementState
|
||||
status.signal = signalState
|
||||
status.peers[key1] = peerState1
|
||||
status.peers[key2] = peerState2
|
||||
|
||||
fullStatus := status.GetFullStatus()
|
||||
|
||||
assert.Equal(t, managementState, fullStatus.ManagementState, "management status should be equal")
|
||||
assert.Equal(t, signalState, fullStatus.SignalState, "signal status should be equal")
|
||||
assert.ElementsMatch(t, []PeerState{peerState1, peerState2}, fullStatus.Peers, "peers states should match")
|
||||
}
|
||||
@@ -4,41 +4,25 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"golang.org/x/sys/unix"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GetInfo retrieves and parses the system information
|
||||
func GetInfo(ctx context.Context) *Info {
|
||||
out := _getInfo()
|
||||
for strings.Contains(out, "broken pipe") {
|
||||
out = _getInfo()
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
utsname := unix.Utsname{}
|
||||
err := unix.Uname(&utsname)
|
||||
if err != nil {
|
||||
fmt.Println("getInfo:", err)
|
||||
}
|
||||
osStr := strings.Replace(out, "\n", "", -1)
|
||||
osStr = strings.Replace(osStr, "\r\n", "", -1)
|
||||
osInfo := strings.Split(osStr, " ")
|
||||
gio := &Info{Kernel: osInfo[0], OSVersion: osInfo[1], Core: osInfo[1], Platform: osInfo[2], OS: osInfo[0], GoOS: runtime.GOOS, CPUs: runtime.NumCPU()}
|
||||
sysName := string(bytes.Split(utsname.Sysname[:], []byte{0})[0])
|
||||
machine := string(bytes.Split(utsname.Machine[:], []byte{0})[0])
|
||||
release := string(bytes.Split(utsname.Release[:], []byte{0})[0])
|
||||
gio := &Info{Kernel: sysName, OSVersion: release, Core: release, Platform: machine, OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU()}
|
||||
gio.Hostname, _ = os.Hostname()
|
||||
gio.WiretrusteeVersion = NetbirdVersion()
|
||||
gio.UIVersion = extractUserAgent(ctx)
|
||||
|
||||
return gio
|
||||
}
|
||||
|
||||
func _getInfo() string {
|
||||
cmd := exec.Command("uname", "-srm")
|
||||
cmd.Stdin = strings.NewReader("some input")
|
||||
var out bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
cmd.Stderr = &stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
fmt.Println("getInfo:", err)
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
//go:build !(linux && 386)
|
||||
// +build !linux !386
|
||||
|
||||
// skipping linux 32 bits build and tests
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -8,17 +8,17 @@ import (
|
||||
)
|
||||
|
||||
// CreateCertManager wraps common logic of generating Let's encrypt certificate.
|
||||
func CreateCertManager(datadir string, letsencryptDomain string) *autocert.Manager {
|
||||
func CreateCertManager(datadir string, letsencryptDomain string) (*autocert.Manager, error) {
|
||||
certDir := filepath.Join(datadir, "letsencrypt")
|
||||
|
||||
if _, err := os.Stat(certDir); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(certDir, os.ModeDir)
|
||||
if err != nil {
|
||||
log.Fatalf("failed creating Let's encrypt certdir: %s: %v", certDir, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("running with Let's encrypt with domain %s. Cert will be stored in %s", letsencryptDomain, certDir)
|
||||
log.Infof("running with LetsEncrypt (%s). Cert will be stored in %s", letsencryptDomain, certDir)
|
||||
|
||||
certManager := &autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
@@ -26,5 +26,5 @@ func CreateCertManager(datadir string, letsencryptDomain string) *autocert.Manag
|
||||
HostPolicy: autocert.HostWhitelist(letsencryptDomain),
|
||||
}
|
||||
|
||||
return certManager
|
||||
return certManager, nil
|
||||
}
|
||||
|
||||
2
go.mod
2
go.mod
@@ -39,6 +39,7 @@ require (
|
||||
github.com/rs/xid v1.3.0
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
||||
github.com/stretchr/testify v1.7.1
|
||||
golang.org/x/net v0.0.0-20220513224357-95641704303c
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467
|
||||
)
|
||||
|
||||
@@ -96,7 +97,6 @@ require (
|
||||
github.com/yuin/goldmark v1.4.1 // indirect
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/net v0.0.0-20220513224357-95641704303c // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 // indirect
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
|
||||
@@ -33,3 +33,8 @@ func (w *WGIface) assignAddr() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WireguardModExists check if we can load wireguard mod (linux only)
|
||||
func WireguardModExists() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ type NativeLink struct {
|
||||
Link *netlink.Link
|
||||
}
|
||||
|
||||
// WireguardModExists check if we can load wireguard mod (linux only)
|
||||
func WireguardModExists() bool {
|
||||
link := newWGLink("mustnotexist")
|
||||
|
||||
|
||||
@@ -57,3 +57,8 @@ func (w *WGIface) UpdateAddr(newAddr string) error {
|
||||
w.Address = addr
|
||||
return w.assignAddr(luid)
|
||||
}
|
||||
|
||||
// WireguardModExists check if we can load wireguard mod (linux only)
|
||||
func WireguardModExists() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
volumes:
|
||||
- $SIGNAL_VOLUMENAME:/var/lib/netbird
|
||||
ports:
|
||||
- 10000:10000
|
||||
- 10000:80
|
||||
# # port and command for Let's Encrypt validation
|
||||
# - 443:443
|
||||
# command: ["--letsencrypt-domain", "$NETBIRD_DOMAIN", "--log-file", "console"]
|
||||
|
||||
@@ -37,7 +37,7 @@ func NewClient(ctx context.Context, addr string, ourPrivateKey wgtypes.Key, tlsE
|
||||
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))
|
||||
}
|
||||
|
||||
mgmCtx, cancel := context.WithTimeout(ctx, time.Second*3)
|
||||
mgmCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
conn, err := grpc.DialContext(
|
||||
mgmCtx,
|
||||
@@ -72,10 +72,10 @@ func (c *GrpcClient) Close() error {
|
||||
func defaultBackoff(ctx context.Context) backoff.BackOff {
|
||||
return backoff.WithContext(&backoff.ExponentialBackOff{
|
||||
InitialInterval: 800 * time.Millisecond,
|
||||
RandomizationFactor: backoff.DefaultRandomizationFactor,
|
||||
Multiplier: backoff.DefaultMultiplier,
|
||||
RandomizationFactor: 1,
|
||||
Multiplier: 1.7,
|
||||
MaxInterval: 10 * time.Second,
|
||||
MaxElapsedTime: 12 * time.Hour, // stop after 12 hours of trying, the error will be propagated to the general retry of the client
|
||||
MaxElapsedTime: 3 * 30 * 24 * time.Hour, // 3 months
|
||||
Stop: backoff.Stop,
|
||||
Clock: backoff.SystemClock,
|
||||
}, ctx)
|
||||
@@ -95,20 +95,26 @@ func (c *GrpcClient) Sync(msgHandler func(msg *proto.SyncResponse) error) error
|
||||
operation := func() error {
|
||||
log.Debugf("management connection state %v", c.conn.GetState())
|
||||
|
||||
if !c.ready() {
|
||||
return fmt.Errorf("no connection to management")
|
||||
connState := c.conn.GetState()
|
||||
if connState == connectivity.Shutdown {
|
||||
return backoff.Permanent(fmt.Errorf("connection to management has been shut down"))
|
||||
} else if !(connState == connectivity.Ready || connState == connectivity.Idle) {
|
||||
c.conn.WaitForStateChange(c.ctx, connState)
|
||||
return fmt.Errorf("connection to management is not ready and in %s state", connState)
|
||||
}
|
||||
|
||||
// todo we already have it since we did the Login, maybe cache it locally?
|
||||
serverPubKey, err := c.GetServerPublicKey()
|
||||
if err != nil {
|
||||
log.Errorf("failed getting Management Service public key: %s", err)
|
||||
log.Debugf("failed getting Management Service public key: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
stream, err := c.connectToStream(*serverPubKey)
|
||||
if err != nil {
|
||||
log.Errorf("failed to open Management Service stream: %s", err)
|
||||
log.Debugf("failed to open Management Service stream: %s", err)
|
||||
if s, ok := gstatus.FromError(err); ok && s.Code() == codes.PermissionDenied {
|
||||
return backoff.Permanent(err) // unrecoverable error, propagate to the upper layer
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -117,10 +123,13 @@ func (c *GrpcClient) Sync(msgHandler func(msg *proto.SyncResponse) error) error
|
||||
// blocking until error
|
||||
err = c.receiveEvents(stream, *serverPubKey, msgHandler)
|
||||
if err != nil {
|
||||
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) {
|
||||
return backoff.Permanent(err)
|
||||
if s, ok := gstatus.FromError(err); ok && s.Code() == codes.PermissionDenied {
|
||||
return backoff.Permanent(err) // unrecoverable error, propagate to the upper layer
|
||||
}
|
||||
// we need this reset because after a successful connection and a consequent error, backoff lib doesn't
|
||||
// reset times and next try will start with a long delay
|
||||
backOff.Reset()
|
||||
log.Warnf("disconnected from the Management service but will retry silently. Reason: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -129,7 +138,7 @@ func (c *GrpcClient) Sync(msgHandler func(msg *proto.SyncResponse) error) error
|
||||
|
||||
err := backoff.Retry(operation, backOff)
|
||||
if err != nil {
|
||||
log.Warnf("exiting Management Service connection retry loop due to Permanent error: %s", err)
|
||||
log.Warnf("exiting the Management service connection retry loop due to the unrecoverable error: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -156,11 +165,11 @@ func (c *GrpcClient) receiveEvents(stream proto.ManagementService_SyncClient, se
|
||||
for {
|
||||
update, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
log.Errorf("Management stream has been closed by server: %s", err)
|
||||
log.Debugf("Management stream has been closed by server: %s", err)
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
log.Warnf("disconnected from Management Service sync stream: %v", err)
|
||||
log.Debugf("disconnected from Management Service sync stream: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -180,13 +189,13 @@ func (c *GrpcClient) receiveEvents(stream proto.ManagementService_SyncClient, se
|
||||
}
|
||||
}
|
||||
|
||||
// GetServerPublicKey returns server Wireguard public key (used later for encrypting messages sent to the server)
|
||||
// GetServerPublicKey returns server's WireGuard public key (used later for encrypting messages sent to the server)
|
||||
func (c *GrpcClient) GetServerPublicKey() (*wgtypes.Key, error) {
|
||||
if !c.ready() {
|
||||
return nil, fmt.Errorf("no connection to management")
|
||||
}
|
||||
|
||||
mgmCtx, cancel := context.WithTimeout(c.ctx, time.Second*2)
|
||||
mgmCtx, cancel := context.WithTimeout(c.ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
resp, err := c.realClient.GetServerKey(mgmCtx, &proto.Empty{})
|
||||
if err != nil {
|
||||
@@ -210,7 +219,7 @@ func (c *GrpcClient) login(serverKey wgtypes.Key, req *proto.LoginRequest) (*pro
|
||||
log.Errorf("failed to encrypt message: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
mgmCtx, cancel := context.WithTimeout(c.ctx, time.Second*2)
|
||||
mgmCtx, cancel := context.WithTimeout(c.ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
resp, err := c.realClient.Login(mgmCtx, &proto.EncryptedMessage{
|
||||
WgPubKey: c.key.PublicKey().String(),
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
httpapi "github.com/netbirdio/netbird/management/server/http"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server"
|
||||
"github.com/netbirdio/netbird/management/server/http"
|
||||
"github.com/netbirdio/netbird/management/server/idp"
|
||||
"github.com/netbirdio/netbird/util"
|
||||
|
||||
@@ -28,11 +32,16 @@ import (
|
||||
"google.golang.org/grpc/keepalive"
|
||||
)
|
||||
|
||||
// ManagementLegacyPort is the port that was used before by the Management gRPC server.
|
||||
// It is used for backward compatibility now.
|
||||
const ManagementLegacyPort = 33073
|
||||
|
||||
var (
|
||||
mgmtPort int
|
||||
mgmtLetsencryptDomain string
|
||||
certFile string
|
||||
certKey string
|
||||
config *server.Config
|
||||
|
||||
kaep = keepalive.EnforcementPolicy{
|
||||
MinTime: 15 * time.Second,
|
||||
@@ -48,34 +57,55 @@ var (
|
||||
|
||||
mgmtCmd = &cobra.Command{
|
||||
Use: "management",
|
||||
Short: "start Netbird Management Server",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Short: "start NetBird Management Server",
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
// detect whether user specified a port
|
||||
userPort := cmd.Flag("port").Changed
|
||||
|
||||
var err error
|
||||
config, err = loadMgmtConfig(mgmtConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed reading provided config file: %s: %v", mgmtConfig, err)
|
||||
}
|
||||
|
||||
tlsEnabled := false
|
||||
if mgmtLetsencryptDomain != "" || (config.HttpConfig.CertFile != "" && config.HttpConfig.CertKey != "") {
|
||||
tlsEnabled = true
|
||||
}
|
||||
|
||||
if !userPort {
|
||||
// different defaults for port when tls enabled/disabled
|
||||
if tlsEnabled {
|
||||
mgmtPort = 443
|
||||
} else {
|
||||
mgmtPort = 80
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
flag.Parse()
|
||||
err := util.InitLog(logLevel, logFile)
|
||||
if err != nil {
|
||||
log.Fatalf("failed initializing log %v", err)
|
||||
return fmt.Errorf("failed initializing log %v", err)
|
||||
}
|
||||
|
||||
err = handleRebrand(cmd)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to migrate files %v", err)
|
||||
}
|
||||
|
||||
config, err := loadMgmtConfig(mgmtConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("failed reading provided config file: %s: %v", mgmtConfig, err)
|
||||
return fmt.Errorf("failed to migrate files %v", err)
|
||||
}
|
||||
|
||||
if _, err = os.Stat(config.Datadir); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(config.Datadir, os.ModeDir)
|
||||
if err != nil {
|
||||
log.Fatalf("failed creating datadir: %s: %v", config.Datadir, err)
|
||||
return fmt.Errorf("failed creating datadir: %s: %v", config.Datadir, err)
|
||||
}
|
||||
}
|
||||
|
||||
store, err := server.NewStore(config.Datadir)
|
||||
if err != nil {
|
||||
log.Fatalf("failed creating a store: %s: %v", config.Datadir, err)
|
||||
return fmt.Errorf("failed creating Store: %s: %v", config.Datadir, err)
|
||||
}
|
||||
peersUpdateManager := server.NewPeersUpdateManager()
|
||||
|
||||
@@ -83,82 +113,181 @@ var (
|
||||
if config.IdpManagerConfig != nil {
|
||||
idpManager, err = idp.NewManager(*config.IdpManagerConfig)
|
||||
if err != nil {
|
||||
log.Fatalln("failed retrieving a new idp manager with err: ", err)
|
||||
return fmt.Errorf("failed retrieving a new idp manager with err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
accountManager, err := server.BuildManager(store, peersUpdateManager, idpManager)
|
||||
if err != nil {
|
||||
log.Fatalln("failed build default manager: ", err)
|
||||
return fmt.Errorf("failed to build default manager: %v", err)
|
||||
}
|
||||
|
||||
var opts []grpc.ServerOption
|
||||
turnManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
|
||||
|
||||
var httpServer *http.Server
|
||||
gRPCOpts := []grpc.ServerOption{grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp)}
|
||||
var certManager *autocert.Manager
|
||||
var tlsConfig *tls.Config
|
||||
tlsEnabled := false
|
||||
if config.HttpConfig.LetsEncryptDomain != "" {
|
||||
// automatically generate a new certificate with Let's Encrypt
|
||||
certManager := encryption.CreateCertManager(config.Datadir, config.HttpConfig.LetsEncryptDomain)
|
||||
transportCredentials := credentials.NewTLS(certManager.TLSConfig())
|
||||
opts = append(opts, grpc.Creds(transportCredentials))
|
||||
|
||||
httpServer = http.NewHttpsServer(config.HttpConfig, certManager, accountManager)
|
||||
} else if config.HttpConfig.CertFile != "" && config.HttpConfig.CertKey != "" {
|
||||
// use provided certificate
|
||||
tlsConfig, err := loadTLSConfig(config.HttpConfig.CertFile, config.HttpConfig.CertKey)
|
||||
certManager, err = encryption.CreateCertManager(config.Datadir, config.HttpConfig.LetsEncryptDomain)
|
||||
if err != nil {
|
||||
log.Fatal("cannot load TLS credentials: ", err)
|
||||
return fmt.Errorf("failed creating LetsEncrypt cert manager: %v", err)
|
||||
}
|
||||
transportCredentials := credentials.NewTLS(certManager.TLSConfig())
|
||||
gRPCOpts = append(gRPCOpts, grpc.Creds(transportCredentials))
|
||||
tlsEnabled = true
|
||||
} else if config.HttpConfig.CertFile != "" && config.HttpConfig.CertKey != "" {
|
||||
tlsConfig, err = loadTLSConfig(config.HttpConfig.CertFile, config.HttpConfig.CertKey)
|
||||
if err != nil {
|
||||
log.Errorf("cannot load TLS credentials: %v", err)
|
||||
return err
|
||||
}
|
||||
transportCredentials := credentials.NewTLS(tlsConfig)
|
||||
opts = append(opts, grpc.Creds(transportCredentials))
|
||||
httpServer = http.NewHttpsServerWithTLSConfig(config.HttpConfig, tlsConfig, accountManager)
|
||||
} else {
|
||||
// start server without SSL
|
||||
httpServer = http.NewHttpServer(config.HttpConfig, accountManager)
|
||||
gRPCOpts = append(gRPCOpts, grpc.Creds(transportCredentials))
|
||||
tlsEnabled = true
|
||||
}
|
||||
|
||||
opts = append(opts, grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
|
||||
grpcServer := grpc.NewServer(opts...)
|
||||
turnManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
|
||||
server, err := server.NewServer(config, accountManager, peersUpdateManager, turnManager)
|
||||
httpAPIHandler, err := httpapi.APIHandler(accountManager,
|
||||
config.HttpConfig.AuthIssuer, config.HttpConfig.AuthAudience, config.HttpConfig.AuthKeysLocation)
|
||||
if err != nil {
|
||||
log.Fatalf("failed creating new server: %v", err)
|
||||
return fmt.Errorf("failed creating HTTP API handler: %v", err)
|
||||
}
|
||||
mgmtProto.RegisterManagementServiceServer(grpcServer, server)
|
||||
log.Printf("started server: localhost:%v", mgmtPort)
|
||||
|
||||
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", mgmtPort))
|
||||
gRPCAPIHandler := grpc.NewServer(gRPCOpts...)
|
||||
srv, err := server.NewServer(config, accountManager, peersUpdateManager, turnManager)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to listen: %v", err)
|
||||
return fmt.Errorf("failed creating gRPC API handler: %v", err)
|
||||
}
|
||||
mgmtProto.RegisterManagementServiceServer(gRPCAPIHandler, srv)
|
||||
|
||||
go func() {
|
||||
if err = grpcServer.Serve(lis); err != nil {
|
||||
log.Fatalf("failed to serve gRpc server: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
err = httpServer.Start()
|
||||
var compatListener net.Listener
|
||||
if mgmtPort != ManagementLegacyPort {
|
||||
// The Management gRPC server was running on port 33073 previously. Old agents that are already connected to it
|
||||
// are using port 33073. For compatibility purposes we keep running a 2nd gRPC server on port 33073.
|
||||
compatListener, err = serveGRPC(gRPCAPIHandler, ManagementLegacyPort)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to serve http server: %v", err)
|
||||
return err
|
||||
}
|
||||
}()
|
||||
log.Infof("running gRPC backward compatibility server: %s", compatListener.Addr().String())
|
||||
}
|
||||
|
||||
rootHandler := handlerFunc(gRPCAPIHandler, httpAPIHandler)
|
||||
var listener net.Listener
|
||||
if certManager != nil {
|
||||
// a call to certManager.Listener() always creates a new listener so we do it once
|
||||
cml := certManager.Listener()
|
||||
if mgmtPort == 443 {
|
||||
// CertManager, HTTP and gRPC API all on the same port
|
||||
rootHandler = certManager.HTTPHandler(rootHandler)
|
||||
listener = cml
|
||||
} else {
|
||||
listener, err = tls.Listen("tcp", fmt.Sprintf(":%d", mgmtPort), certManager.TLSConfig())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed creating TLS listener on port %d: %v", mgmtPort, err)
|
||||
}
|
||||
log.Infof("running HTTP server (LetsEncrypt challenge handler): %s", cml.Addr().String())
|
||||
serveHTTP(cml, certManager.HTTPHandler(nil))
|
||||
}
|
||||
} else if tlsConfig != nil {
|
||||
listener, err = tls.Listen("tcp", fmt.Sprintf(":%d", mgmtPort), tlsConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed creating TLS listener on port %d: %v", mgmtPort, err)
|
||||
}
|
||||
} else {
|
||||
listener, err = net.Listen("tcp", fmt.Sprintf(":%d", mgmtPort))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed creating TCP listener on port %d: %v", mgmtPort, err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("running HTTP server and gRPC server on the same port: %s", listener.Addr().String())
|
||||
serveGRPCWithHTTP(listener, rootHandler, tlsEnabled)
|
||||
|
||||
SetupCloseHandler()
|
||||
<-stopCh
|
||||
log.Println("Receive signal to stop running Management server")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
err = httpServer.Stop(ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("failed stopping the http server %v", err)
|
||||
}
|
||||
|
||||
grpcServer.Stop()
|
||||
<-stopCh
|
||||
_ = listener.Close()
|
||||
if certManager != nil {
|
||||
_ = certManager.Listener().Close()
|
||||
}
|
||||
gRPCAPIHandler.Stop()
|
||||
log.Infof("stopped Management Service")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func notifyStop(msg string) {
|
||||
select {
|
||||
case stopCh <- 1:
|
||||
log.Error(msg)
|
||||
default:
|
||||
// stop has been already called, nothing to report
|
||||
}
|
||||
}
|
||||
|
||||
func serveGRPC(grpcServer *grpc.Server, port int) (net.Listener, error) {
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
err := grpcServer.Serve(listener)
|
||||
if err != nil {
|
||||
notifyStop(fmt.Sprintf("failed running gRPC server on port %d: %v", port, err))
|
||||
}
|
||||
}()
|
||||
return listener, nil
|
||||
}
|
||||
|
||||
func serveHTTP(httpListener net.Listener, handler http.Handler) {
|
||||
go func() {
|
||||
err := http.Serve(httpListener, handler)
|
||||
if err != nil {
|
||||
notifyStop(fmt.Sprintf("failed running HTTP server: %v", err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func serveGRPCWithHTTP(listener net.Listener, handler http.Handler, tlsEnabled bool) {
|
||||
go func() {
|
||||
var err error
|
||||
if tlsEnabled {
|
||||
err = http.Serve(listener, handler)
|
||||
} else {
|
||||
// the following magic is needed to support HTTP2 without TLS
|
||||
// and still share a single port between gRPC and HTTP APIs
|
||||
h1s := &http.Server{
|
||||
Handler: h2c.NewHandler(handler, &http2.Server{}),
|
||||
}
|
||||
err = h1s.Serve(listener)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
select {
|
||||
case stopCh <- 1:
|
||||
log.Errorf("failed to serve HTTP and gRPC server: %v", err)
|
||||
default:
|
||||
// stop has been already called, nothing to report
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func handlerFunc(gRPCHandler *grpc.Server, httpHandler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
grpcHeader := strings.HasPrefix(request.Header.Get("Content-Type"), "application/grpc") ||
|
||||
strings.HasPrefix(request.Header.Get("Content-Type"), "application/grpc+proto")
|
||||
fmt.Println(grpcHeader)
|
||||
if request.ProtoMajor == 2 && grpcHeader {
|
||||
gRPCHandler.ServeHTTP(writer, request)
|
||||
} else {
|
||||
httpHandler.ServeHTTP(writer, request)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func loadMgmtConfig(mgmtConfigPath string) (*server.Config, error) {
|
||||
config := &server.Config{}
|
||||
_, err := util.ReadJson(mgmtConfigPath, config)
|
||||
|
||||
@@ -60,7 +60,7 @@ func init() {
|
||||
oldDefaultMgmtConfig = oldDefaultMgmtConfigDir + "/management.json"
|
||||
oldDefaultLogFile = oldDefaultLogDir + "/management.log"
|
||||
|
||||
mgmtCmd.Flags().IntVar(&mgmtPort, "port", 33073, "server port to listen on")
|
||||
mgmtCmd.Flags().IntVar(&mgmtPort, "port", 80, "server port to listen on (defaults to 443 if TLS is enabled, 80 otherwise")
|
||||
mgmtCmd.Flags().StringVar(&mgmtDataDir, "datadir", defaultMgmtDataDir, "server data directory location")
|
||||
mgmtCmd.Flags().StringVar(&mgmtConfig, "config", defaultMgmtConfig, "Netbird config file location. Config params specified via command line (e.g. datadir) have a precedence over configuration from this file")
|
||||
mgmtCmd.Flags().StringVar(&mgmtLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
||||
|
||||
@@ -49,7 +49,6 @@ type HttpServerConfig struct {
|
||||
CertFile string
|
||||
//CertKey is the location of the certificate private key
|
||||
CertKey string
|
||||
Address string
|
||||
// AuthAudience identifies the recipients that the JWT is intended for (aud in JWT)
|
||||
AuthAudience string
|
||||
// AuthIssuer identifies principal that issued the JWT.
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Server an instance of a Management server
|
||||
type Server struct {
|
||||
// GRPCServer an instance of a Management gRPC API server
|
||||
type GRPCServer struct {
|
||||
accountManager AccountManager
|
||||
wgKey wgtypes.Key
|
||||
proto.UnimplementedManagementServiceServer
|
||||
@@ -30,7 +30,7 @@ type Server struct {
|
||||
}
|
||||
|
||||
// NewServer creates a new Management server
|
||||
func NewServer(config *Config, accountManager AccountManager, peersUpdateManager *PeersUpdateManager, turnCredentialsManager TURNCredentialsManager) (*Server, error) {
|
||||
func NewServer(config *Config, accountManager AccountManager, peersUpdateManager *PeersUpdateManager, turnCredentialsManager TURNCredentialsManager) (*GRPCServer, error) {
|
||||
key, err := wgtypes.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -50,7 +50,7 @@ func NewServer(config *Config, accountManager AccountManager, peersUpdateManager
|
||||
log.Debug("unable to use http config to create new jwt middleware")
|
||||
}
|
||||
|
||||
return &Server{
|
||||
return &GRPCServer{
|
||||
wgKey: key,
|
||||
// peerKey -> event channel
|
||||
peersUpdateManager: peersUpdateManager,
|
||||
@@ -61,7 +61,7 @@ func NewServer(config *Config, accountManager AccountManager, peersUpdateManager
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetServerKey(ctx context.Context, req *proto.Empty) (*proto.ServerKeyResponse, error) {
|
||||
func (s *GRPCServer) GetServerKey(ctx context.Context, req *proto.Empty) (*proto.ServerKeyResponse, error) {
|
||||
// todo introduce something more meaningful with the key expiration/rotation
|
||||
now := time.Now().Add(24 * time.Hour)
|
||||
secs := int64(now.Second())
|
||||
@@ -76,7 +76,7 @@ func (s *Server) GetServerKey(ctx context.Context, req *proto.Empty) (*proto.Ser
|
||||
|
||||
// Sync validates the existence of a connecting peer, sends an initial state (all available for the connecting peers) and
|
||||
// notifies the connected peer of any updates (e.g. new peers under the same account)
|
||||
func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_SyncServer) error {
|
||||
func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_SyncServer) error {
|
||||
log.Debugf("Sync request from peer %s", req.WgPubKey)
|
||||
|
||||
peerKey, err := wgtypes.ParseKey(req.GetWgPubKey())
|
||||
@@ -150,7 +150,7 @@ func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_S
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Peer, error) {
|
||||
func (s *GRPCServer) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Peer, error) {
|
||||
var (
|
||||
reqSetupKey string
|
||||
userId string
|
||||
@@ -245,7 +245,7 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Pe
|
||||
// In case it is, the login is successful
|
||||
// In case it isn't, the endpoint checks whether setup key is provided within the request and tries to register a peer.
|
||||
// In case of the successful registration login is also successful
|
||||
func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
|
||||
func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
|
||||
log.Debugf("Login request from peer %s", req.WgPubKey)
|
||||
|
||||
peerKey, err := wgtypes.ParseKey(req.GetWgPubKey())
|
||||
@@ -429,12 +429,12 @@ func toSyncResponse(config *Config, peer *Peer, peers []*Peer, turnCredentials *
|
||||
}
|
||||
|
||||
// IsHealthy indicates whether the service is healthy
|
||||
func (s *Server) IsHealthy(ctx context.Context, req *proto.Empty) (*proto.Empty, error) {
|
||||
func (s *GRPCServer) IsHealthy(ctx context.Context, req *proto.Empty) (*proto.Empty, error) {
|
||||
return &proto.Empty{}, nil
|
||||
}
|
||||
|
||||
// sendInitialSync sends initial proto.SyncResponse to the peer requesting synchronization
|
||||
func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.ManagementService_SyncServer) error {
|
||||
func (s *GRPCServer) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.ManagementService_SyncServer) error {
|
||||
networkMap, err := s.accountManager.GetNetworkMap(peer.Key)
|
||||
if err != nil {
|
||||
log.Warnf("error getting a list of peers for a peer %s", peer.Key)
|
||||
@@ -472,7 +472,7 @@ func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.Mana
|
||||
// GetDeviceAuthorizationFlow returns a device authorization flow information
|
||||
// This is used for initiating an Oauth 2 device authorization grant flow
|
||||
// which will be used by our clients to Login
|
||||
func (s *Server) GetDeviceAuthorizationFlow(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
|
||||
func (s *GRPCServer) GetDeviceAuthorizationFlow(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
|
||||
peerKey, err := wgtypes.ParseKey(req.GetWgPubKey())
|
||||
if err != nil {
|
||||
errMSG := fmt.Sprintf("error while parsing peer's Wireguard public key %s on GetDeviceAuthorizationFlow request.", req.WgPubKey)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
64
management/server/http/handler.go
Normal file
64
management/server/http/handler.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
s "github.com/netbirdio/netbird/management/server"
|
||||
"github.com/netbirdio/netbird/management/server/http/middleware"
|
||||
"github.com/rs/cors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// APIHandler creates the Management service HTTP API handler registering all the available endpoints.
|
||||
func APIHandler(accountManager s.AccountManager, authIssuer string, authAudience string, authKeysLocation string) (http.Handler, error) {
|
||||
jwtMiddleware, err := middleware.NewJwtMiddleware(
|
||||
authIssuer,
|
||||
authAudience,
|
||||
authKeysLocation,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
corsMiddleware := cors.AllowAll()
|
||||
|
||||
acMiddleware := middleware.NewAccessControll(
|
||||
authAudience,
|
||||
accountManager.IsUserAdmin)
|
||||
|
||||
apiHandler := mux.NewRouter()
|
||||
apiHandler.Use(jwtMiddleware.Handler, corsMiddleware.Handler, acMiddleware.Handler)
|
||||
|
||||
groupsHandler := NewGroups(accountManager, authAudience)
|
||||
rulesHandler := NewRules(accountManager, authAudience)
|
||||
peersHandler := NewPeers(accountManager, authAudience)
|
||||
keysHandler := NewSetupKeysHandler(accountManager, authAudience)
|
||||
userHandler := NewUserHandler(accountManager, authAudience)
|
||||
|
||||
apiHandler.HandleFunc("/api/peers", peersHandler.GetPeers).Methods("GET", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/peers/{id}", peersHandler.HandlePeer).
|
||||
Methods("GET", "PUT", "DELETE", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/users", userHandler.GetUsers).Methods("GET", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/setup-keys", keysHandler.GetKeys).Methods("GET", "POST", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/setup-keys/{id}", keysHandler.HandleKey).Methods("GET", "PUT", "OPTIONS")
|
||||
|
||||
apiHandler.HandleFunc("/api/setup-keys", keysHandler.GetKeys).Methods("POST", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/setup-keys/{id}", keysHandler.HandleKey).
|
||||
Methods("GET", "PUT", "DELETE", "OPTIONS")
|
||||
|
||||
apiHandler.HandleFunc("/api/rules", rulesHandler.GetAllRulesHandler).Methods("GET", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/rules", rulesHandler.CreateRuleHandler).Methods("POST", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/rules/{id}", rulesHandler.UpdateRuleHandler).Methods("PUT", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/rules/{id}", rulesHandler.PatchRuleHandler).Methods("PATCH", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/rules/{id}", rulesHandler.GetRuleHandler).Methods("GET", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/rules/{id}", rulesHandler.DeleteRuleHandler).Methods("DELETE", "OPTIONS")
|
||||
|
||||
apiHandler.HandleFunc("/api/groups", groupsHandler.GetAllGroupsHandler).Methods("GET", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/groups", groupsHandler.CreateGroupHandler).Methods("POST", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/groups/{id}", groupsHandler.UpdateGroupHandler).Methods("PUT", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/groups/{id}", groupsHandler.PatchGroupHandler).Methods("PATCH", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/groups/{id}", groupsHandler.GetGroupHandler).Methods("GET", "OPTIONS")
|
||||
apiHandler.HandleFunc("/api/groups/{id}", groupsHandler.DeleteGroupHandler).Methods("DELETE", "OPTIONS")
|
||||
|
||||
return apiHandler, nil
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -1,167 +0,0 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
s "github.com/netbirdio/netbird/management/server"
|
||||
"github.com/netbirdio/netbird/management/server/http/handler"
|
||||
"github.com/netbirdio/netbird/management/server/http/middleware"
|
||||
"github.com/rs/cors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
server *http.Server
|
||||
config *s.HttpServerConfig
|
||||
certManager *autocert.Manager
|
||||
tlsConfig *tls.Config
|
||||
accountManager s.AccountManager
|
||||
}
|
||||
|
||||
// NewHttpsServer creates a new HTTPs server (with HTTPS support) and a certManager that is responsible for generating and renewing Let's Encrypt certificate
|
||||
// The listening address will be :443 no matter what was specified in s.HttpServerConfig.Address
|
||||
func NewHttpsServer(
|
||||
config *s.HttpServerConfig,
|
||||
certManager *autocert.Manager,
|
||||
accountManager s.AccountManager,
|
||||
) *Server {
|
||||
server := &http.Server{
|
||||
Addr: config.Address,
|
||||
WriteTimeout: time.Second * 15,
|
||||
ReadTimeout: time.Second * 15,
|
||||
IdleTimeout: time.Second * 60,
|
||||
}
|
||||
return &Server{
|
||||
server: server,
|
||||
config: config,
|
||||
certManager: certManager,
|
||||
accountManager: accountManager,
|
||||
}
|
||||
}
|
||||
|
||||
// NewHttpsServerWithTLSConfig creates a new HTTPs server with a provided tls.Config.
|
||||
// Usually used when you already have a certificate
|
||||
func NewHttpsServerWithTLSConfig(
|
||||
config *s.HttpServerConfig,
|
||||
tlsConfig *tls.Config,
|
||||
accountManager s.AccountManager,
|
||||
) *Server {
|
||||
server := &http.Server{
|
||||
Addr: config.Address,
|
||||
WriteTimeout: time.Second * 15,
|
||||
ReadTimeout: time.Second * 15,
|
||||
IdleTimeout: time.Second * 60,
|
||||
}
|
||||
return &Server{
|
||||
server: server,
|
||||
config: config,
|
||||
tlsConfig: tlsConfig,
|
||||
accountManager: accountManager,
|
||||
}
|
||||
}
|
||||
|
||||
// NewHttpServer creates a new HTTP server (without HTTPS)
|
||||
func NewHttpServer(config *s.HttpServerConfig, accountManager s.AccountManager) *Server {
|
||||
return NewHttpsServer(config, nil, accountManager)
|
||||
}
|
||||
|
||||
// Stop stops the http server
|
||||
func (s *Server) Stop(ctx context.Context) error {
|
||||
err := s.server.Shutdown(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start defines http handlers and starts the http server. Blocks until server is shutdown.
|
||||
func (s *Server) Start() error {
|
||||
jwtMiddleware, err := middleware.NewJwtMiddleware(
|
||||
s.config.AuthIssuer,
|
||||
s.config.AuthAudience,
|
||||
s.config.AuthKeysLocation,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
corsMiddleware := cors.AllowAll()
|
||||
|
||||
acMiddleware := middleware.NewAccessControll(
|
||||
s.config.AuthAudience,
|
||||
s.accountManager.IsUserAdmin)
|
||||
|
||||
r := mux.NewRouter()
|
||||
r.Use(jwtMiddleware.Handler, corsMiddleware.Handler, acMiddleware.Handler)
|
||||
|
||||
groupsHandler := handler.NewGroups(s.accountManager, s.config.AuthAudience)
|
||||
rulesHandler := handler.NewRules(s.accountManager, s.config.AuthAudience)
|
||||
peersHandler := handler.NewPeers(s.accountManager, s.config.AuthAudience)
|
||||
keysHandler := handler.NewSetupKeysHandler(s.accountManager, s.config.AuthAudience)
|
||||
userHandler := handler.NewUserHandler(s.accountManager, s.config.AuthAudience)
|
||||
|
||||
r.HandleFunc("/api/peers", peersHandler.GetPeers).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/api/peers/{id}", peersHandler.HandlePeer).
|
||||
Methods("GET", "PUT", "DELETE", "OPTIONS")
|
||||
r.HandleFunc("/api/users", userHandler.GetUsers).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/api/setup-keys", keysHandler.GetKeys).Methods("GET", "POST", "OPTIONS")
|
||||
r.HandleFunc("/api/setup-keys/{id}", keysHandler.HandleKey).Methods("GET", "PUT", "OPTIONS")
|
||||
|
||||
r.HandleFunc("/api/setup-keys", keysHandler.GetKeys).Methods("POST", "OPTIONS")
|
||||
r.HandleFunc("/api/setup-keys/{id}", keysHandler.HandleKey).
|
||||
Methods("GET", "PUT", "DELETE", "OPTIONS")
|
||||
|
||||
r.HandleFunc("/api/rules", rulesHandler.GetAllRulesHandler).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/api/rules", rulesHandler.CreateRuleHandler).Methods("POST", "OPTIONS")
|
||||
r.HandleFunc("/api/rules/{id}", rulesHandler.UpdateRuleHandler).Methods("PUT", "OPTIONS")
|
||||
r.HandleFunc("/api/rules/{id}", rulesHandler.PatchRuleHandler).Methods("PATCH", "OPTIONS")
|
||||
r.HandleFunc("/api/rules/{id}", rulesHandler.GetRuleHandler).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/api/rules/{id}", rulesHandler.DeleteRuleHandler).Methods("DELETE", "OPTIONS")
|
||||
|
||||
r.HandleFunc("/api/groups", groupsHandler.GetAllGroupsHandler).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/api/groups", groupsHandler.CreateGroupHandler).Methods("POST", "OPTIONS")
|
||||
r.HandleFunc("/api/groups/{id}", groupsHandler.UpdateGroupHandler).Methods("PUT", "OPTIONS")
|
||||
r.HandleFunc("/api/groups/{id}", groupsHandler.PatchGroupHandler).Methods("PATCH", "OPTIONS")
|
||||
r.HandleFunc("/api/groups/{id}", groupsHandler.GetGroupHandler).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/api/groups/{id}", groupsHandler.DeleteGroupHandler).Methods("DELETE", "OPTIONS")
|
||||
http.Handle("/", r)
|
||||
|
||||
if s.certManager != nil {
|
||||
// if HTTPS is enabled we reuse the listener from the cert manager
|
||||
listener := s.certManager.Listener()
|
||||
log.Infof(
|
||||
"HTTPs server listening on %s with Let's Encrypt autocert configured",
|
||||
listener.Addr(),
|
||||
)
|
||||
if err = http.Serve(listener, s.certManager.HTTPHandler(r)); err != nil {
|
||||
log.Errorf("failed to serve https server: %v", err)
|
||||
return err
|
||||
}
|
||||
} else if s.tlsConfig != nil {
|
||||
listener, err := tls.Listen("tcp", s.config.Address, s.tlsConfig)
|
||||
if err != nil {
|
||||
log.Errorf("failed to serve https server: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Infof("HTTPs server listening on %s", listener.Addr())
|
||||
|
||||
if err = http.Serve(listener, r); err != nil {
|
||||
log.Errorf("failed to serve https server: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Infof("HTTP server listening on %s", s.server.Addr)
|
||||
if err = s.server.ListenAndServe(); err != nil {
|
||||
log.Errorf("failed to serve http server: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -359,7 +359,7 @@ func TestServer_GetDeviceAuthorizationFlow(t *testing.T) {
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
mgmtServer := &Server{
|
||||
mgmtServer := &GRPCServer{
|
||||
wgKey: testingServerKey,
|
||||
config: &Config{
|
||||
DeviceAuthorizationFlow: testCase.inputFlow,
|
||||
|
||||
@@ -58,7 +58,7 @@ func NewClient(ctx context.Context, addr string, key wgtypes.Key, tlsEnabled boo
|
||||
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))
|
||||
}
|
||||
|
||||
sigCtx, cancel := context.WithTimeout(ctx, time.Second*3)
|
||||
sigCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
conn, err := grpc.DialContext(
|
||||
sigCtx,
|
||||
@@ -75,6 +75,8 @@ func NewClient(ctx context.Context, addr string, key wgtypes.Key, tlsEnabled boo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("connected to Signal Service: %v", conn.Target())
|
||||
|
||||
return &GrpcClient{
|
||||
realClient: proto.NewSignalExchangeClient(conn),
|
||||
ctx: ctx,
|
||||
@@ -89,14 +91,13 @@ func NewClient(ctx context.Context, addr string, key wgtypes.Key, tlsEnabled boo
|
||||
func defaultBackoff(ctx context.Context) backoff.BackOff {
|
||||
return backoff.WithContext(&backoff.ExponentialBackOff{
|
||||
InitialInterval: 800 * time.Millisecond,
|
||||
RandomizationFactor: backoff.DefaultRandomizationFactor,
|
||||
Multiplier: backoff.DefaultMultiplier,
|
||||
RandomizationFactor: 1,
|
||||
Multiplier: 1.7,
|
||||
MaxInterval: 10 * time.Second,
|
||||
MaxElapsedTime: 12 * time.Hour, //stop after 12 hours of trying, the error will be propagated to the general retry of the client
|
||||
MaxElapsedTime: 3 * 30 * 24 * time.Hour, // 3 months
|
||||
Stop: backoff.Stop,
|
||||
Clock: backoff.SystemClock,
|
||||
}, ctx)
|
||||
|
||||
}
|
||||
|
||||
// Receive Connects to the Signal Exchange message stream and starts receiving messages.
|
||||
@@ -112,8 +113,12 @@ func (c *GrpcClient) Receive(msgHandler func(msg *proto.Message) error) error {
|
||||
c.notifyStreamDisconnected()
|
||||
|
||||
log.Debugf("signal connection state %v", c.signalConn.GetState())
|
||||
if !c.Ready() {
|
||||
return fmt.Errorf("no connection to signal")
|
||||
connState := c.signalConn.GetState()
|
||||
if connState == connectivity.Shutdown {
|
||||
return backoff.Permanent(fmt.Errorf("connection to signal has been shut down"))
|
||||
} else if !(connState == connectivity.Ready || connState == connectivity.Idle) {
|
||||
c.signalConn.WaitForStateChange(c.ctx, connState)
|
||||
return fmt.Errorf("connection to signal is not ready and in %s state", connState)
|
||||
}
|
||||
|
||||
// connect to Signal stream identifying ourselves with a public Wireguard key
|
||||
@@ -131,7 +136,8 @@ func (c *GrpcClient) Receive(msgHandler func(msg *proto.Message) error) error {
|
||||
// start receiving messages from the Signal stream (from other peers through signal)
|
||||
err = c.receive(stream, msgHandler)
|
||||
if err != nil {
|
||||
log.Warnf("disconnected from the Signal Exchange due to an error: %v", err)
|
||||
// we need this reset because after a successful connection and a consequent error, backoff lib doesn't
|
||||
// reset times and next try will start with a long delay
|
||||
backOff.Reset()
|
||||
return err
|
||||
}
|
||||
@@ -141,7 +147,7 @@ func (c *GrpcClient) Receive(msgHandler func(msg *proto.Message) error) error {
|
||||
|
||||
err := backoff.Retry(operation, backOff)
|
||||
if err != nil {
|
||||
log.Errorf("exiting Signal Service connection retry loop due to unrecoverable error: %s", err)
|
||||
log.Errorf("exiting the Signal service connection retry loop due to the unrecoverable error: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -308,13 +314,13 @@ func (c *GrpcClient) receive(stream proto.SignalExchange_ConnectStreamClient,
|
||||
for {
|
||||
msg, err := stream.Recv()
|
||||
if s, ok := status.FromError(err); ok && s.Code() == codes.Canceled {
|
||||
log.Warnf("stream canceled (usually indicates shutdown)")
|
||||
log.Debugf("stream canceled (usually indicates shutdown)")
|
||||
return err
|
||||
} else if s.Code() == codes.Unavailable {
|
||||
log.Warnf("Signal Service is unavailable")
|
||||
log.Debugf("Signal Service is unavailable")
|
||||
return err
|
||||
} else if err == io.EOF {
|
||||
log.Warnf("Signal Service stream closed by server")
|
||||
log.Debugf("Signal Service stream closed by server")
|
||||
return err
|
||||
} else if err != nil {
|
||||
return err
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/encryption"
|
||||
@@ -29,6 +31,7 @@ var (
|
||||
signalLetsencryptDomain string
|
||||
signalSSLDir string
|
||||
defaultSignalSSLDir string
|
||||
tlsEnabled bool
|
||||
|
||||
signalKaep = grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
|
||||
MinTime: 5 * time.Second,
|
||||
@@ -44,9 +47,26 @@ var (
|
||||
|
||||
runCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "start Netbird Signal Server daemon",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Short: "start NetBird Signal Server daemon",
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
// detect whether user specified a port
|
||||
userPort := cmd.Flag("port").Changed
|
||||
if signalLetsencryptDomain != "" {
|
||||
tlsEnabled = true
|
||||
}
|
||||
|
||||
if !userPort {
|
||||
// different defaults for signalPort
|
||||
if tlsEnabled {
|
||||
signalPort = 443
|
||||
} else {
|
||||
signalPort = 80
|
||||
}
|
||||
}
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
flag.Parse()
|
||||
|
||||
err := util.InitLog(logLevel, logFile)
|
||||
if err != nil {
|
||||
log.Fatalf("failed initializing log %v", err)
|
||||
@@ -62,47 +82,120 @@ var (
|
||||
}
|
||||
|
||||
var opts []grpc.ServerOption
|
||||
if signalLetsencryptDomain != "" {
|
||||
if _, err := os.Stat(signalSSLDir); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(signalSSLDir, os.ModeDir)
|
||||
if err != nil {
|
||||
log.Fatalf("failed creating datadir: %s: %v", signalSSLDir, err)
|
||||
}
|
||||
var certManager *autocert.Manager
|
||||
if tlsEnabled {
|
||||
// Let's encrypt enabled -> generate certificate automatically
|
||||
certManager, err = encryption.CreateCertManager(signalSSLDir, signalLetsencryptDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
certManager := encryption.CreateCertManager(signalSSLDir, signalLetsencryptDomain)
|
||||
transportCredentials := credentials.NewTLS(certManager.TLSConfig())
|
||||
opts = append(opts, grpc.Creds(transportCredentials))
|
||||
|
||||
listener := certManager.Listener()
|
||||
log.Infof("http server listening on %s", listener.Addr())
|
||||
go func() {
|
||||
if err := http.Serve(listener, certManager.HTTPHandler(nil)); err != nil {
|
||||
log.Errorf("failed to serve https server: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
opts = append(opts, signalKaep, signalKasp)
|
||||
grpcServer := grpc.NewServer(opts...)
|
||||
|
||||
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", signalPort))
|
||||
if err != nil {
|
||||
log.Fatalf("failed to listen: %v", err)
|
||||
}
|
||||
|
||||
proto.RegisterSignalExchangeServer(grpcServer, server.NewServer())
|
||||
log.Printf("started server: localhost:%v", signalPort)
|
||||
if err := grpcServer.Serve(lis); err != nil {
|
||||
log.Fatalf("failed to serve: %v", err)
|
||||
|
||||
var compatListener net.Listener
|
||||
if signalPort != 10000 {
|
||||
// The Signal gRPC server was running on port 10000 previously. Old agents that are already connected to Signal
|
||||
// are using port 10000. For compatibility purposes we keep running a 2nd gRPC server on port 10000.
|
||||
compatListener, err = serveGRPC(grpcServer, 10000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("running gRPC backward compatibility server: %s", compatListener.Addr().String())
|
||||
}
|
||||
|
||||
var grpcListener net.Listener
|
||||
var httpListener net.Listener
|
||||
if tlsEnabled {
|
||||
httpListener = certManager.Listener()
|
||||
if signalPort == 443 {
|
||||
// running gRPC and HTTP cert manager on the same port
|
||||
serveHTTP(httpListener, certManager.HTTPHandler(grpcHandlerFunc(grpcServer)))
|
||||
log.Infof("running HTTP server (LetsEncrypt challenge handler) and gRPC server on the same port: %s", httpListener.Addr().String())
|
||||
} else {
|
||||
serveHTTP(httpListener, certManager.HTTPHandler(nil))
|
||||
log.Infof("running HTTP server (LetsEncrypt challenge handler): %s", httpListener.Addr().String())
|
||||
}
|
||||
}
|
||||
|
||||
if signalPort != 443 || !tlsEnabled {
|
||||
grpcListener, err = serveGRPC(grpcServer, signalPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("running gRPC server: %s", grpcListener.Addr().String())
|
||||
}
|
||||
|
||||
log.Infof("started Signal Service")
|
||||
|
||||
SetupCloseHandler()
|
||||
|
||||
<-stopCh
|
||||
log.Println("Receive signal to stop running the Signal server")
|
||||
if grpcListener != nil {
|
||||
_ = grpcListener.Close()
|
||||
log.Infof("stopped gRPC server")
|
||||
}
|
||||
if httpListener != nil {
|
||||
_ = httpListener.Close()
|
||||
log.Infof("stopped HTTP server")
|
||||
}
|
||||
if compatListener != nil {
|
||||
_ = compatListener.Close()
|
||||
log.Infof("stopped gRPC backward compatibility server")
|
||||
}
|
||||
log.Infof("stopped Signal Service")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func grpcHandlerFunc(grpcServer *grpc.Server) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
grpcHeader := strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") ||
|
||||
strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc+proto")
|
||||
if r.ProtoMajor == 2 && grpcHeader {
|
||||
grpcServer.ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func notifyStop(msg string) {
|
||||
select {
|
||||
case stopCh <- 1:
|
||||
log.Error(msg)
|
||||
default:
|
||||
// stop has been already called, nothing to report
|
||||
}
|
||||
}
|
||||
|
||||
func serveHTTP(httpListener net.Listener, handler http.Handler) {
|
||||
go func() {
|
||||
err := http.Serve(httpListener, handler)
|
||||
if err != nil {
|
||||
notifyStop(fmt.Sprintf("failed running HTTP server %v", err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func serveGRPC(grpcServer *grpc.Server, port int) (net.Listener, error) {
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
err := grpcServer.Serve(listener)
|
||||
if err != nil {
|
||||
notifyStop(fmt.Sprintf("failed running gRPC server on port %d: %v", port, err))
|
||||
}
|
||||
}()
|
||||
return listener, nil
|
||||
}
|
||||
|
||||
func cpFile(src, dst string) error {
|
||||
var err error
|
||||
var srcfd *os.File
|
||||
@@ -191,7 +284,7 @@ func migrateToNetbird(oldPath, newPath string) bool {
|
||||
}
|
||||
|
||||
func init() {
|
||||
runCmd.PersistentFlags().IntVar(&signalPort, "port", 10000, "Server port to listen on (e.g. 10000)")
|
||||
runCmd.PersistentFlags().IntVar(&signalPort, "port", 80, "Server port to listen on (defaults to 443 if TLS is enabled, 80 otherwise")
|
||||
runCmd.Flags().StringVar(&signalSSLDir, "ssl-dir", defaultSignalSSLDir, "server ssl directory location. *Required only for Let's Encrypt certificates.")
|
||||
runCmd.Flags().StringVar(&signalLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package util
|
||||
|
||||
import "os"
|
||||
|
||||
// SliceDiff returns the elements in slice `x` that are not in slice `y`
|
||||
func SliceDiff(x, y []string) []string {
|
||||
mapY := make(map[string]struct{}, len(y))
|
||||
@@ -14,3 +16,9 @@ func SliceDiff(x, y []string) []string {
|
||||
}
|
||||
return diff
|
||||
}
|
||||
|
||||
// FileExists returns true if specified file exists
|
||||
func FileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user