mirror of
https://github.com/netbirdio/netbird.git
synced 2025-04-01 11:46:39 +02:00
Extend netbird status command to include health information (#1471)
* Adds management, signal, and relay (STUN/TURN) health probes to the status command. * Adds a reason when the management or signal connections are disconnected. * Adds last wireguard handshake and received/sent bytes per peer
This commit is contained in:
parent
d4194cba6a
commit
a7d6632298
@ -274,6 +274,8 @@ go test -exec sudo ./...
|
|||||||
```
|
```
|
||||||
> On Windows use a powershell with administrator privileges
|
> On Windows use a powershell with administrator privileges
|
||||||
|
|
||||||
|
> Non-GTK environments will need the `libayatana-appindicator3-dev` (debian/ubuntu) package installed
|
||||||
|
|
||||||
## Checklist before submitting a PR
|
## Checklist before submitting a PR
|
||||||
As a critical network service and open-source project, we must enforce a few things before submitting the pull-requests:
|
As a critical network service and open-source project, we must enforce a few things before submitting the pull-requests:
|
||||||
- Keep functions as simple as possible, with a single purpose
|
- Keep functions as simple as possible, with a single purpose
|
||||||
|
@ -22,14 +22,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type peerStateDetailOutput struct {
|
type peerStateDetailOutput struct {
|
||||||
FQDN string `json:"fqdn" yaml:"fqdn"`
|
FQDN string `json:"fqdn" yaml:"fqdn"`
|
||||||
IP string `json:"netbirdIp" yaml:"netbirdIp"`
|
IP string `json:"netbirdIp" yaml:"netbirdIp"`
|
||||||
PubKey string `json:"publicKey" yaml:"publicKey"`
|
PubKey string `json:"publicKey" yaml:"publicKey"`
|
||||||
Status string `json:"status" yaml:"status"`
|
Status string `json:"status" yaml:"status"`
|
||||||
LastStatusUpdate time.Time `json:"lastStatusUpdate" yaml:"lastStatusUpdate"`
|
LastStatusUpdate time.Time `json:"lastStatusUpdate" yaml:"lastStatusUpdate"`
|
||||||
ConnType string `json:"connectionType" yaml:"connectionType"`
|
ConnType string `json:"connectionType" yaml:"connectionType"`
|
||||||
Direct bool `json:"direct" yaml:"direct"`
|
Direct bool `json:"direct" yaml:"direct"`
|
||||||
IceCandidateType iceCandidateType `json:"iceCandidateType" yaml:"iceCandidateType"`
|
IceCandidateType iceCandidateType `json:"iceCandidateType" yaml:"iceCandidateType"`
|
||||||
|
IceCandidateEndpoint iceCandidateType `json:"iceCandidateEndpoint" yaml:"iceCandidateEndpoint"`
|
||||||
|
LastWireguardHandshake time.Time `json:"lastWireguardHandshake" yaml:"lastWireguardHandshake"`
|
||||||
|
TransferReceived int64 `json:"transferReceived" yaml:"transferReceived"`
|
||||||
|
TransferSent int64 `json:"transferSent" yaml:"transferSent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type peersStateOutput struct {
|
type peersStateOutput struct {
|
||||||
@ -41,11 +45,25 @@ type peersStateOutput struct {
|
|||||||
type signalStateOutput struct {
|
type signalStateOutput struct {
|
||||||
URL string `json:"url" yaml:"url"`
|
URL string `json:"url" yaml:"url"`
|
||||||
Connected bool `json:"connected" yaml:"connected"`
|
Connected bool `json:"connected" yaml:"connected"`
|
||||||
|
Error string `json:"error" yaml:"error"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type managementStateOutput struct {
|
type managementStateOutput struct {
|
||||||
URL string `json:"url" yaml:"url"`
|
URL string `json:"url" yaml:"url"`
|
||||||
Connected bool `json:"connected" yaml:"connected"`
|
Connected bool `json:"connected" yaml:"connected"`
|
||||||
|
Error string `json:"error" yaml:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type relayStateOutputDetail struct {
|
||||||
|
URI string `json:"uri" yaml:"uri"`
|
||||||
|
Available bool `json:"available" yaml:"available"`
|
||||||
|
Error string `json:"error" yaml:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type relayStateOutput struct {
|
||||||
|
Total int `json:"total" yaml:"total"`
|
||||||
|
Available int `json:"available" yaml:"available"`
|
||||||
|
Details []relayStateOutputDetail `json:"details" yaml:"details"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type iceCandidateType struct {
|
type iceCandidateType struct {
|
||||||
@ -59,6 +77,7 @@ type statusOutputOverview struct {
|
|||||||
DaemonVersion string `json:"daemonVersion" yaml:"daemonVersion"`
|
DaemonVersion string `json:"daemonVersion" yaml:"daemonVersion"`
|
||||||
ManagementState managementStateOutput `json:"management" yaml:"management"`
|
ManagementState managementStateOutput `json:"management" yaml:"management"`
|
||||||
SignalState signalStateOutput `json:"signal" yaml:"signal"`
|
SignalState signalStateOutput `json:"signal" yaml:"signal"`
|
||||||
|
Relays relayStateOutput `json:"relays" yaml:"relays"`
|
||||||
IP string `json:"netbirdIp" yaml:"netbirdIp"`
|
IP string `json:"netbirdIp" yaml:"netbirdIp"`
|
||||||
PubKey string `json:"publicKey" yaml:"publicKey"`
|
PubKey string `json:"publicKey" yaml:"publicKey"`
|
||||||
KernelInterface bool `json:"usesKernelInterface" yaml:"usesKernelInterface"`
|
KernelInterface bool `json:"usesKernelInterface" yaml:"usesKernelInterface"`
|
||||||
@ -146,7 +165,7 @@ func statusFunc(cmd *cobra.Command, args []string) error {
|
|||||||
case yamlFlag:
|
case yamlFlag:
|
||||||
statusOutputString, err = parseToYAML(outputInformationHolder)
|
statusOutputString, err = parseToYAML(outputInformationHolder)
|
||||||
default:
|
default:
|
||||||
statusOutputString = parseGeneralSummary(outputInformationHolder, false)
|
statusOutputString = parseGeneralSummary(outputInformationHolder, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -220,14 +239,17 @@ func convertToStatusOutputOverview(resp *proto.StatusResponse) statusOutputOverv
|
|||||||
managementOverview := managementStateOutput{
|
managementOverview := managementStateOutput{
|
||||||
URL: managementState.GetURL(),
|
URL: managementState.GetURL(),
|
||||||
Connected: managementState.GetConnected(),
|
Connected: managementState.GetConnected(),
|
||||||
|
Error: managementState.Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
signalState := pbFullStatus.GetSignalState()
|
signalState := pbFullStatus.GetSignalState()
|
||||||
signalOverview := signalStateOutput{
|
signalOverview := signalStateOutput{
|
||||||
URL: signalState.GetURL(),
|
URL: signalState.GetURL(),
|
||||||
Connected: signalState.GetConnected(),
|
Connected: signalState.GetConnected(),
|
||||||
|
Error: signalState.Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
relayOverview := mapRelays(pbFullStatus.GetRelays())
|
||||||
peersOverview := mapPeers(resp.GetFullStatus().GetPeers())
|
peersOverview := mapPeers(resp.GetFullStatus().GetPeers())
|
||||||
|
|
||||||
overview := statusOutputOverview{
|
overview := statusOutputOverview{
|
||||||
@ -236,6 +258,7 @@ func convertToStatusOutputOverview(resp *proto.StatusResponse) statusOutputOverv
|
|||||||
DaemonVersion: resp.GetDaemonVersion(),
|
DaemonVersion: resp.GetDaemonVersion(),
|
||||||
ManagementState: managementOverview,
|
ManagementState: managementOverview,
|
||||||
SignalState: signalOverview,
|
SignalState: signalOverview,
|
||||||
|
Relays: relayOverview,
|
||||||
IP: pbFullStatus.GetLocalPeerState().GetIP(),
|
IP: pbFullStatus.GetLocalPeerState().GetIP(),
|
||||||
PubKey: pbFullStatus.GetLocalPeerState().GetPubKey(),
|
PubKey: pbFullStatus.GetLocalPeerState().GetPubKey(),
|
||||||
KernelInterface: pbFullStatus.GetLocalPeerState().GetKernelInterface(),
|
KernelInterface: pbFullStatus.GetLocalPeerState().GetKernelInterface(),
|
||||||
@ -245,12 +268,43 @@ func convertToStatusOutputOverview(resp *proto.StatusResponse) statusOutputOverv
|
|||||||
return overview
|
return overview
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mapRelays(relays []*proto.RelayState) relayStateOutput {
|
||||||
|
var relayStateDetail []relayStateOutputDetail
|
||||||
|
|
||||||
|
var relaysAvailable int
|
||||||
|
for _, relay := range relays {
|
||||||
|
available := relay.GetAvailable()
|
||||||
|
relayStateDetail = append(relayStateDetail,
|
||||||
|
relayStateOutputDetail{
|
||||||
|
URI: relay.URI,
|
||||||
|
Available: available,
|
||||||
|
Error: relay.GetError(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if available {
|
||||||
|
relaysAvailable++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return relayStateOutput{
|
||||||
|
Total: len(relays),
|
||||||
|
Available: relaysAvailable,
|
||||||
|
Details: relayStateDetail,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func mapPeers(peers []*proto.PeerState) peersStateOutput {
|
func mapPeers(peers []*proto.PeerState) peersStateOutput {
|
||||||
var peersStateDetail []peerStateDetailOutput
|
var peersStateDetail []peerStateDetailOutput
|
||||||
localICE := ""
|
localICE := ""
|
||||||
remoteICE := ""
|
remoteICE := ""
|
||||||
|
localICEEndpoint := ""
|
||||||
|
remoteICEEndpoint := ""
|
||||||
connType := ""
|
connType := ""
|
||||||
peersConnected := 0
|
peersConnected := 0
|
||||||
|
lastHandshake := time.Time{}
|
||||||
|
transferReceived := int64(0)
|
||||||
|
transferSent := int64(0)
|
||||||
for _, pbPeerState := range peers {
|
for _, pbPeerState := range peers {
|
||||||
isPeerConnected := pbPeerState.ConnStatus == peer.StatusConnected.String()
|
isPeerConnected := pbPeerState.ConnStatus == peer.StatusConnected.String()
|
||||||
if skipDetailByFilters(pbPeerState, isPeerConnected) {
|
if skipDetailByFilters(pbPeerState, isPeerConnected) {
|
||||||
@ -261,10 +315,15 @@ func mapPeers(peers []*proto.PeerState) peersStateOutput {
|
|||||||
|
|
||||||
localICE = pbPeerState.GetLocalIceCandidateType()
|
localICE = pbPeerState.GetLocalIceCandidateType()
|
||||||
remoteICE = pbPeerState.GetRemoteIceCandidateType()
|
remoteICE = pbPeerState.GetRemoteIceCandidateType()
|
||||||
|
localICEEndpoint = pbPeerState.GetLocalIceCandidateEndpoint()
|
||||||
|
remoteICEEndpoint = pbPeerState.GetRemoteIceCandidateEndpoint()
|
||||||
connType = "P2P"
|
connType = "P2P"
|
||||||
if pbPeerState.Relayed {
|
if pbPeerState.Relayed {
|
||||||
connType = "Relayed"
|
connType = "Relayed"
|
||||||
}
|
}
|
||||||
|
lastHandshake = pbPeerState.GetLastWireguardHandshake().AsTime().Local()
|
||||||
|
transferReceived = pbPeerState.GetBytesRx()
|
||||||
|
transferSent = pbPeerState.GetBytesTx()
|
||||||
}
|
}
|
||||||
|
|
||||||
timeLocal := pbPeerState.GetConnStatusUpdate().AsTime().Local()
|
timeLocal := pbPeerState.GetConnStatusUpdate().AsTime().Local()
|
||||||
@ -279,7 +338,14 @@ func mapPeers(peers []*proto.PeerState) peersStateOutput {
|
|||||||
Local: localICE,
|
Local: localICE,
|
||||||
Remote: remoteICE,
|
Remote: remoteICE,
|
||||||
},
|
},
|
||||||
FQDN: pbPeerState.GetFqdn(),
|
IceCandidateEndpoint: iceCandidateType{
|
||||||
|
Local: localICEEndpoint,
|
||||||
|
Remote: remoteICEEndpoint,
|
||||||
|
},
|
||||||
|
FQDN: pbPeerState.GetFqdn(),
|
||||||
|
LastWireguardHandshake: lastHandshake,
|
||||||
|
TransferReceived: transferReceived,
|
||||||
|
TransferSent: transferSent,
|
||||||
}
|
}
|
||||||
|
|
||||||
peersStateDetail = append(peersStateDetail, peerState)
|
peersStateDetail = append(peersStateDetail, peerState)
|
||||||
@ -329,22 +395,32 @@ func parseToYAML(overview statusOutputOverview) (string, error) {
|
|||||||
return string(yamlBytes), nil
|
return string(yamlBytes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseGeneralSummary(overview statusOutputOverview, showURL bool) string {
|
func parseGeneralSummary(overview statusOutputOverview, showURL bool, showRelays bool) string {
|
||||||
|
|
||||||
managementConnString := "Disconnected"
|
var managementConnString string
|
||||||
if overview.ManagementState.Connected {
|
if overview.ManagementState.Connected {
|
||||||
managementConnString = "Connected"
|
managementConnString = "Connected"
|
||||||
if showURL {
|
if showURL {
|
||||||
managementConnString = fmt.Sprintf("%s to %s", managementConnString, overview.ManagementState.URL)
|
managementConnString = fmt.Sprintf("%s to %s", managementConnString, overview.ManagementState.URL)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
managementConnString = "Disconnected"
|
||||||
|
if overview.ManagementState.Error != "" {
|
||||||
|
managementConnString = fmt.Sprintf("%s, reason: %s", managementConnString, overview.ManagementState.Error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signalConnString := "Disconnected"
|
var signalConnString string
|
||||||
if overview.SignalState.Connected {
|
if overview.SignalState.Connected {
|
||||||
signalConnString = "Connected"
|
signalConnString = "Connected"
|
||||||
if showURL {
|
if showURL {
|
||||||
signalConnString = fmt.Sprintf("%s to %s", signalConnString, overview.SignalState.URL)
|
signalConnString = fmt.Sprintf("%s to %s", signalConnString, overview.SignalState.URL)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
signalConnString = "Disconnected"
|
||||||
|
if overview.SignalState.Error != "" {
|
||||||
|
signalConnString = fmt.Sprintf("%s, reason: %s", signalConnString, overview.SignalState.Error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaceTypeString := "Userspace"
|
interfaceTypeString := "Userspace"
|
||||||
@ -356,6 +432,23 @@ func parseGeneralSummary(overview statusOutputOverview, showURL bool) string {
|
|||||||
interfaceIP = "N/A"
|
interfaceIP = "N/A"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var relayAvailableString string
|
||||||
|
if showRelays {
|
||||||
|
for _, relay := range overview.Relays.Details {
|
||||||
|
available := "Available"
|
||||||
|
reason := ""
|
||||||
|
if !relay.Available {
|
||||||
|
available = "Unavailable"
|
||||||
|
reason = fmt.Sprintf(", reason: %s", relay.Error)
|
||||||
|
}
|
||||||
|
relayAvailableString += fmt.Sprintf("\n [%s] is %s%s", relay.URI, available, reason)
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
relayAvailableString = fmt.Sprintf("%d/%d Available", overview.Relays.Available, overview.Relays.Total)
|
||||||
|
}
|
||||||
|
|
||||||
peersCountString := fmt.Sprintf("%d/%d Connected", overview.Peers.Connected, overview.Peers.Total)
|
peersCountString := fmt.Sprintf("%d/%d Connected", overview.Peers.Connected, overview.Peers.Total)
|
||||||
|
|
||||||
summary := fmt.Sprintf(
|
summary := fmt.Sprintf(
|
||||||
@ -363,6 +456,7 @@ func parseGeneralSummary(overview statusOutputOverview, showURL bool) string {
|
|||||||
"CLI version: %s\n"+
|
"CLI version: %s\n"+
|
||||||
"Management: %s\n"+
|
"Management: %s\n"+
|
||||||
"Signal: %s\n"+
|
"Signal: %s\n"+
|
||||||
|
"Relays: %s\n"+
|
||||||
"FQDN: %s\n"+
|
"FQDN: %s\n"+
|
||||||
"NetBird IP: %s\n"+
|
"NetBird IP: %s\n"+
|
||||||
"Interface type: %s\n"+
|
"Interface type: %s\n"+
|
||||||
@ -371,6 +465,7 @@ func parseGeneralSummary(overview statusOutputOverview, showURL bool) string {
|
|||||||
version.NetbirdVersion(),
|
version.NetbirdVersion(),
|
||||||
managementConnString,
|
managementConnString,
|
||||||
signalConnString,
|
signalConnString,
|
||||||
|
relayAvailableString,
|
||||||
overview.FQDN,
|
overview.FQDN,
|
||||||
interfaceIP,
|
interfaceIP,
|
||||||
interfaceTypeString,
|
interfaceTypeString,
|
||||||
@ -381,7 +476,7 @@ func parseGeneralSummary(overview statusOutputOverview, showURL bool) string {
|
|||||||
|
|
||||||
func parseToFullDetailSummary(overview statusOutputOverview) string {
|
func parseToFullDetailSummary(overview statusOutputOverview) string {
|
||||||
parsedPeersString := parsePeers(overview.Peers)
|
parsedPeersString := parsePeers(overview.Peers)
|
||||||
summary := parseGeneralSummary(overview, true)
|
summary := parseGeneralSummary(overview, true, true)
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"Peers detail:"+
|
"Peers detail:"+
|
||||||
@ -409,6 +504,25 @@ func parsePeers(peers peersStateOutput) string {
|
|||||||
remoteICE = peerState.IceCandidateType.Remote
|
remoteICE = peerState.IceCandidateType.Remote
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localICEEndpoint := "-"
|
||||||
|
if peerState.IceCandidateEndpoint.Local != "" {
|
||||||
|
localICEEndpoint = peerState.IceCandidateEndpoint.Local
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteICEEndpoint := "-"
|
||||||
|
if peerState.IceCandidateEndpoint.Remote != "" {
|
||||||
|
remoteICEEndpoint = peerState.IceCandidateEndpoint.Remote
|
||||||
|
}
|
||||||
|
lastStatusUpdate := "-"
|
||||||
|
if !peerState.LastStatusUpdate.IsZero() {
|
||||||
|
lastStatusUpdate = peerState.LastStatusUpdate.Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
|
||||||
|
lastWireguardHandshake := "-"
|
||||||
|
if !peerState.LastWireguardHandshake.IsZero() && peerState.LastWireguardHandshake != time.Unix(0, 0) {
|
||||||
|
lastWireguardHandshake = peerState.LastWireguardHandshake.Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
|
||||||
peerString := fmt.Sprintf(
|
peerString := fmt.Sprintf(
|
||||||
"\n %s:\n"+
|
"\n %s:\n"+
|
||||||
" NetBird IP: %s\n"+
|
" NetBird IP: %s\n"+
|
||||||
@ -418,7 +532,10 @@ func parsePeers(peers peersStateOutput) string {
|
|||||||
" Connection type: %s\n"+
|
" Connection type: %s\n"+
|
||||||
" Direct: %t\n"+
|
" Direct: %t\n"+
|
||||||
" ICE candidate (Local/Remote): %s/%s\n"+
|
" ICE candidate (Local/Remote): %s/%s\n"+
|
||||||
" Last connection update: %s\n",
|
" ICE candidate endpoints (Local/Remote): %s/%s\n"+
|
||||||
|
" Last connection update: %s\n"+
|
||||||
|
" Last Wireguard handshake: %s\n"+
|
||||||
|
" Transfer status (received/sent) %s/%s\n",
|
||||||
peerState.FQDN,
|
peerState.FQDN,
|
||||||
peerState.IP,
|
peerState.IP,
|
||||||
peerState.PubKey,
|
peerState.PubKey,
|
||||||
@ -427,7 +544,12 @@ func parsePeers(peers peersStateOutput) string {
|
|||||||
peerState.Direct,
|
peerState.Direct,
|
||||||
localICE,
|
localICE,
|
||||||
remoteICE,
|
remoteICE,
|
||||||
peerState.LastStatusUpdate.Format("2006-01-02 15:04:05"),
|
localICEEndpoint,
|
||||||
|
remoteICEEndpoint,
|
||||||
|
lastStatusUpdate,
|
||||||
|
lastWireguardHandshake,
|
||||||
|
toIEC(peerState.TransferReceived),
|
||||||
|
toIEC(peerState.TransferSent),
|
||||||
)
|
)
|
||||||
|
|
||||||
peersString += peerString
|
peersString += peerString
|
||||||
@ -467,3 +589,17 @@ func skipDetailByFilters(peerState *proto.PeerState, isConnected bool) bool {
|
|||||||
|
|
||||||
return statusEval || ipEval || nameEval
|
return statusEval || ipEval || nameEval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toIEC(b int64) string {
|
||||||
|
const unit = 1024
|
||||||
|
if b < unit {
|
||||||
|
return fmt.Sprintf("%d B", b)
|
||||||
|
}
|
||||||
|
div, exp := int64(unit), 0
|
||||||
|
for n := b / unit; n >= unit; n /= unit {
|
||||||
|
div *= unit
|
||||||
|
exp++
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%.1f %ciB",
|
||||||
|
float64(b)/float64(div), "KMGTPE"[exp])
|
||||||
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/proto"
|
"github.com/netbirdio/netbird/client/proto"
|
||||||
@ -25,35 +28,59 @@ var resp = &proto.StatusResponse{
|
|||||||
FullStatus: &proto.FullStatus{
|
FullStatus: &proto.FullStatus{
|
||||||
Peers: []*proto.PeerState{
|
Peers: []*proto.PeerState{
|
||||||
{
|
{
|
||||||
IP: "192.168.178.101",
|
IP: "192.168.178.101",
|
||||||
PubKey: "Pubkey1",
|
PubKey: "Pubkey1",
|
||||||
Fqdn: "peer-1.awesome-domain.com",
|
Fqdn: "peer-1.awesome-domain.com",
|
||||||
ConnStatus: "Connected",
|
ConnStatus: "Connected",
|
||||||
ConnStatusUpdate: timestamppb.New(time.Date(2001, time.Month(1), 1, 1, 1, 1, 0, time.UTC)),
|
ConnStatusUpdate: timestamppb.New(time.Date(2001, time.Month(1), 1, 1, 1, 1, 0, time.UTC)),
|
||||||
Relayed: false,
|
Relayed: false,
|
||||||
Direct: true,
|
Direct: true,
|
||||||
LocalIceCandidateType: "",
|
LocalIceCandidateType: "",
|
||||||
RemoteIceCandidateType: "",
|
RemoteIceCandidateType: "",
|
||||||
|
LocalIceCandidateEndpoint: "",
|
||||||
|
RemoteIceCandidateEndpoint: "",
|
||||||
|
LastWireguardHandshake: timestamppb.New(time.Date(2001, time.Month(1), 1, 1, 1, 2, 0, time.UTC)),
|
||||||
|
BytesRx: 200,
|
||||||
|
BytesTx: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
IP: "192.168.178.102",
|
IP: "192.168.178.102",
|
||||||
PubKey: "Pubkey2",
|
PubKey: "Pubkey2",
|
||||||
Fqdn: "peer-2.awesome-domain.com",
|
Fqdn: "peer-2.awesome-domain.com",
|
||||||
ConnStatus: "Connected",
|
ConnStatus: "Connected",
|
||||||
ConnStatusUpdate: timestamppb.New(time.Date(2002, time.Month(2), 2, 2, 2, 2, 0, time.UTC)),
|
ConnStatusUpdate: timestamppb.New(time.Date(2002, time.Month(2), 2, 2, 2, 2, 0, time.UTC)),
|
||||||
Relayed: true,
|
Relayed: true,
|
||||||
Direct: false,
|
Direct: false,
|
||||||
LocalIceCandidateType: "relay",
|
LocalIceCandidateType: "relay",
|
||||||
RemoteIceCandidateType: "prflx",
|
RemoteIceCandidateType: "prflx",
|
||||||
|
LocalIceCandidateEndpoint: "10.0.0.1:10001",
|
||||||
|
RemoteIceCandidateEndpoint: "10.0.10.1:10002",
|
||||||
|
LastWireguardHandshake: timestamppb.New(time.Date(2002, time.Month(2), 2, 2, 2, 3, 0, time.UTC)),
|
||||||
|
BytesRx: 2000,
|
||||||
|
BytesTx: 1000,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ManagementState: &proto.ManagementState{
|
ManagementState: &proto.ManagementState{
|
||||||
URL: "my-awesome-management.com:443",
|
URL: "my-awesome-management.com:443",
|
||||||
Connected: true,
|
Connected: true,
|
||||||
|
Error: "",
|
||||||
},
|
},
|
||||||
SignalState: &proto.SignalState{
|
SignalState: &proto.SignalState{
|
||||||
URL: "my-awesome-signal.com:443",
|
URL: "my-awesome-signal.com:443",
|
||||||
Connected: true,
|
Connected: true,
|
||||||
|
Error: "",
|
||||||
|
},
|
||||||
|
Relays: []*proto.RelayState{
|
||||||
|
{
|
||||||
|
URI: "stun:my-awesome-stun.com:3478",
|
||||||
|
Available: true,
|
||||||
|
Error: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
URI: "turns:my-awesome-turn.com:443?transport=tcp",
|
||||||
|
Available: false,
|
||||||
|
Error: "context: deadline exceeded",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
LocalPeerState: &proto.LocalPeerState{
|
LocalPeerState: &proto.LocalPeerState{
|
||||||
IP: "192.168.178.100/16",
|
IP: "192.168.178.100/16",
|
||||||
@ -82,6 +109,13 @@ var overview = statusOutputOverview{
|
|||||||
Local: "",
|
Local: "",
|
||||||
Remote: "",
|
Remote: "",
|
||||||
},
|
},
|
||||||
|
IceCandidateEndpoint: iceCandidateType{
|
||||||
|
Local: "",
|
||||||
|
Remote: "",
|
||||||
|
},
|
||||||
|
LastWireguardHandshake: time.Date(2001, 1, 1, 1, 1, 2, 0, time.UTC),
|
||||||
|
TransferReceived: 200,
|
||||||
|
TransferSent: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
IP: "192.168.178.102",
|
IP: "192.168.178.102",
|
||||||
@ -95,6 +129,13 @@ var overview = statusOutputOverview{
|
|||||||
Local: "relay",
|
Local: "relay",
|
||||||
Remote: "prflx",
|
Remote: "prflx",
|
||||||
},
|
},
|
||||||
|
IceCandidateEndpoint: iceCandidateType{
|
||||||
|
Local: "10.0.0.1:10001",
|
||||||
|
Remote: "10.0.10.1:10002",
|
||||||
|
},
|
||||||
|
LastWireguardHandshake: time.Date(2002, 2, 2, 2, 2, 3, 0, time.UTC),
|
||||||
|
TransferReceived: 2000,
|
||||||
|
TransferSent: 1000,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -103,10 +144,28 @@ var overview = statusOutputOverview{
|
|||||||
ManagementState: managementStateOutput{
|
ManagementState: managementStateOutput{
|
||||||
URL: "my-awesome-management.com:443",
|
URL: "my-awesome-management.com:443",
|
||||||
Connected: true,
|
Connected: true,
|
||||||
|
Error: "",
|
||||||
},
|
},
|
||||||
SignalState: signalStateOutput{
|
SignalState: signalStateOutput{
|
||||||
URL: "my-awesome-signal.com:443",
|
URL: "my-awesome-signal.com:443",
|
||||||
Connected: true,
|
Connected: true,
|
||||||
|
Error: "",
|
||||||
|
},
|
||||||
|
Relays: relayStateOutput{
|
||||||
|
Total: 2,
|
||||||
|
Available: 1,
|
||||||
|
Details: []relayStateOutputDetail{
|
||||||
|
{
|
||||||
|
URI: "stun:my-awesome-stun.com:3478",
|
||||||
|
Available: true,
|
||||||
|
Error: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
URI: "turns:my-awesome-turn.com:443?transport=tcp",
|
||||||
|
Available: false,
|
||||||
|
Error: "context: deadline exceeded",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
IP: "192.168.178.100/16",
|
IP: "192.168.178.100/16",
|
||||||
PubKey: "Some-Pub-Key",
|
PubKey: "Some-Pub-Key",
|
||||||
@ -145,107 +204,163 @@ func TestSortingOfPeers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParsingToJSON(t *testing.T) {
|
func TestParsingToJSON(t *testing.T) {
|
||||||
json, _ := parseToJSON(overview)
|
jsonString, _ := parseToJSON(overview)
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
expectedJSON := "{\"" +
|
expectedJSONString := `
|
||||||
"peers\":" +
|
{
|
||||||
"{" +
|
"peers": {
|
||||||
"\"total\":2," +
|
"total": 2,
|
||||||
"\"connected\":2," +
|
"connected": 2,
|
||||||
"\"details\":" +
|
"details": [
|
||||||
"[" +
|
{
|
||||||
"{" +
|
"fqdn": "peer-1.awesome-domain.com",
|
||||||
"\"fqdn\":\"peer-1.awesome-domain.com\"," +
|
"netbirdIp": "192.168.178.101",
|
||||||
"\"netbirdIp\":\"192.168.178.101\"," +
|
"publicKey": "Pubkey1",
|
||||||
"\"publicKey\":\"Pubkey1\"," +
|
"status": "Connected",
|
||||||
"\"status\":\"Connected\"," +
|
"lastStatusUpdate": "2001-01-01T01:01:01Z",
|
||||||
"\"lastStatusUpdate\":\"2001-01-01T01:01:01Z\"," +
|
"connectionType": "P2P",
|
||||||
"\"connectionType\":\"P2P\"," +
|
"direct": true,
|
||||||
"\"direct\":true," +
|
"iceCandidateType": {
|
||||||
"\"iceCandidateType\":" +
|
"local": "",
|
||||||
"{" +
|
"remote": ""
|
||||||
"\"local\":\"\"," +
|
},
|
||||||
"\"remote\":\"\"" +
|
"iceCandidateEndpoint": {
|
||||||
"}" +
|
"local": "",
|
||||||
"}," +
|
"remote": ""
|
||||||
"{" +
|
},
|
||||||
"\"fqdn\":\"peer-2.awesome-domain.com\"," +
|
"lastWireguardHandshake": "2001-01-01T01:01:02Z",
|
||||||
"\"netbirdIp\":\"192.168.178.102\"," +
|
"transferReceived": 200,
|
||||||
"\"publicKey\":\"Pubkey2\"," +
|
"transferSent": 100
|
||||||
"\"status\":\"Connected\"," +
|
},
|
||||||
"\"lastStatusUpdate\":\"2002-02-02T02:02:02Z\"," +
|
{
|
||||||
"\"connectionType\":\"Relayed\"," +
|
"fqdn": "peer-2.awesome-domain.com",
|
||||||
"\"direct\":false," +
|
"netbirdIp": "192.168.178.102",
|
||||||
"\"iceCandidateType\":" +
|
"publicKey": "Pubkey2",
|
||||||
"{" +
|
"status": "Connected",
|
||||||
"\"local\":\"relay\"," +
|
"lastStatusUpdate": "2002-02-02T02:02:02Z",
|
||||||
"\"remote\":\"prflx\"" +
|
"connectionType": "Relayed",
|
||||||
"}" +
|
"direct": false,
|
||||||
"}" +
|
"iceCandidateType": {
|
||||||
"]" +
|
"local": "relay",
|
||||||
"}," +
|
"remote": "prflx"
|
||||||
"\"cliVersion\":\"development\"," +
|
},
|
||||||
"\"daemonVersion\":\"0.14.1\"," +
|
"iceCandidateEndpoint": {
|
||||||
"\"management\":" +
|
"local": "10.0.0.1:10001",
|
||||||
"{" +
|
"remote": "10.0.10.1:10002"
|
||||||
"\"url\":\"my-awesome-management.com:443\"," +
|
},
|
||||||
"\"connected\":true" +
|
"lastWireguardHandshake": "2002-02-02T02:02:03Z",
|
||||||
"}," +
|
"transferReceived": 2000,
|
||||||
"\"signal\":" +
|
"transferSent": 1000
|
||||||
"{\"" +
|
}
|
||||||
"url\":\"my-awesome-signal.com:443\"," +
|
]
|
||||||
"\"connected\":true" +
|
},
|
||||||
"}," +
|
"cliVersion": "development",
|
||||||
"\"netbirdIp\":\"192.168.178.100/16\"," +
|
"daemonVersion": "0.14.1",
|
||||||
"\"publicKey\":\"Some-Pub-Key\"," +
|
"management": {
|
||||||
"\"usesKernelInterface\":true," +
|
"url": "my-awesome-management.com:443",
|
||||||
"\"fqdn\":\"some-localhost.awesome-domain.com\"" +
|
"connected": true,
|
||||||
"}"
|
"error": ""
|
||||||
|
},
|
||||||
|
"signal": {
|
||||||
|
"url": "my-awesome-signal.com:443",
|
||||||
|
"connected": true,
|
||||||
|
"error": ""
|
||||||
|
},
|
||||||
|
"relays": {
|
||||||
|
"total": 2,
|
||||||
|
"available": 1,
|
||||||
|
"details": [
|
||||||
|
{
|
||||||
|
"uri": "stun:my-awesome-stun.com:3478",
|
||||||
|
"available": true,
|
||||||
|
"error": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "turns:my-awesome-turn.com:443?transport=tcp",
|
||||||
|
"available": false,
|
||||||
|
"error": "context: deadline exceeded"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"netbirdIp": "192.168.178.100/16",
|
||||||
|
"publicKey": "Some-Pub-Key",
|
||||||
|
"usesKernelInterface": true,
|
||||||
|
"fqdn": "some-localhost.awesome-domain.com"
|
||||||
|
}`
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
assert.Equal(t, expectedJSON, json)
|
var expectedJSON bytes.Buffer
|
||||||
|
require.NoError(t, json.Compact(&expectedJSON, []byte(expectedJSONString)))
|
||||||
|
|
||||||
|
assert.Equal(t, expectedJSON.String(), jsonString)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsingToYAML(t *testing.T) {
|
func TestParsingToYAML(t *testing.T) {
|
||||||
yaml, _ := parseToYAML(overview)
|
yaml, _ := parseToYAML(overview)
|
||||||
|
|
||||||
expectedYAML := "peers:\n" +
|
expectedYAML :=
|
||||||
" total: 2\n" +
|
`peers:
|
||||||
" connected: 2\n" +
|
total: 2
|
||||||
" details:\n" +
|
connected: 2
|
||||||
" - fqdn: peer-1.awesome-domain.com\n" +
|
details:
|
||||||
" netbirdIp: 192.168.178.101\n" +
|
- fqdn: peer-1.awesome-domain.com
|
||||||
" publicKey: Pubkey1\n" +
|
netbirdIp: 192.168.178.101
|
||||||
" status: Connected\n" +
|
publicKey: Pubkey1
|
||||||
" lastStatusUpdate: 2001-01-01T01:01:01Z\n" +
|
status: Connected
|
||||||
" connectionType: P2P\n" +
|
lastStatusUpdate: 2001-01-01T01:01:01Z
|
||||||
" direct: true\n" +
|
connectionType: P2P
|
||||||
" iceCandidateType:\n" +
|
direct: true
|
||||||
" local: \"\"\n" +
|
iceCandidateType:
|
||||||
" remote: \"\"\n" +
|
local: ""
|
||||||
" - fqdn: peer-2.awesome-domain.com\n" +
|
remote: ""
|
||||||
" netbirdIp: 192.168.178.102\n" +
|
iceCandidateEndpoint:
|
||||||
" publicKey: Pubkey2\n" +
|
local: ""
|
||||||
" status: Connected\n" +
|
remote: ""
|
||||||
" lastStatusUpdate: 2002-02-02T02:02:02Z\n" +
|
lastWireguardHandshake: 2001-01-01T01:01:02Z
|
||||||
" connectionType: Relayed\n" +
|
transferReceived: 200
|
||||||
" direct: false\n" +
|
transferSent: 100
|
||||||
" iceCandidateType:\n" +
|
- fqdn: peer-2.awesome-domain.com
|
||||||
" local: relay\n" +
|
netbirdIp: 192.168.178.102
|
||||||
" remote: prflx\n" +
|
publicKey: Pubkey2
|
||||||
"cliVersion: development\n" +
|
status: Connected
|
||||||
"daemonVersion: 0.14.1\n" +
|
lastStatusUpdate: 2002-02-02T02:02:02Z
|
||||||
"management:\n" +
|
connectionType: Relayed
|
||||||
" url: my-awesome-management.com:443\n" +
|
direct: false
|
||||||
" connected: true\n" +
|
iceCandidateType:
|
||||||
"signal:\n" +
|
local: relay
|
||||||
" url: my-awesome-signal.com:443\n" +
|
remote: prflx
|
||||||
" connected: true\n" +
|
iceCandidateEndpoint:
|
||||||
"netbirdIp: 192.168.178.100/16\n" +
|
local: 10.0.0.1:10001
|
||||||
"publicKey: Some-Pub-Key\n" +
|
remote: 10.0.10.1:10002
|
||||||
"usesKernelInterface: true\n" +
|
lastWireguardHandshake: 2002-02-02T02:02:03Z
|
||||||
"fqdn: some-localhost.awesome-domain.com\n"
|
transferReceived: 2000
|
||||||
|
transferSent: 1000
|
||||||
|
cliVersion: development
|
||||||
|
daemonVersion: 0.14.1
|
||||||
|
management:
|
||||||
|
url: my-awesome-management.com:443
|
||||||
|
connected: true
|
||||||
|
error: ""
|
||||||
|
signal:
|
||||||
|
url: my-awesome-signal.com:443
|
||||||
|
connected: true
|
||||||
|
error: ""
|
||||||
|
relays:
|
||||||
|
total: 2
|
||||||
|
available: 1
|
||||||
|
details:
|
||||||
|
- uri: stun:my-awesome-stun.com:3478
|
||||||
|
available: true
|
||||||
|
error: ""
|
||||||
|
- uri: turns:my-awesome-turn.com:443?transport=tcp
|
||||||
|
available: false
|
||||||
|
error: 'context: deadline exceeded'
|
||||||
|
netbirdIp: 192.168.178.100/16
|
||||||
|
publicKey: Some-Pub-Key
|
||||||
|
usesKernelInterface: true
|
||||||
|
fqdn: some-localhost.awesome-domain.com
|
||||||
|
`
|
||||||
|
|
||||||
assert.Equal(t, expectedYAML, yaml)
|
assert.Equal(t, expectedYAML, yaml)
|
||||||
}
|
}
|
||||||
@ -253,50 +368,64 @@ func TestParsingToYAML(t *testing.T) {
|
|||||||
func TestParsingToDetail(t *testing.T) {
|
func TestParsingToDetail(t *testing.T) {
|
||||||
detail := parseToFullDetailSummary(overview)
|
detail := parseToFullDetailSummary(overview)
|
||||||
|
|
||||||
expectedDetail := "Peers detail:\n" +
|
expectedDetail :=
|
||||||
" peer-1.awesome-domain.com:\n" +
|
`Peers detail:
|
||||||
" NetBird IP: 192.168.178.101\n" +
|
peer-1.awesome-domain.com:
|
||||||
" Public key: Pubkey1\n" +
|
NetBird IP: 192.168.178.101
|
||||||
" Status: Connected\n" +
|
Public key: Pubkey1
|
||||||
" -- detail --\n" +
|
Status: Connected
|
||||||
" Connection type: P2P\n" +
|
-- detail --
|
||||||
" Direct: true\n" +
|
Connection type: P2P
|
||||||
" ICE candidate (Local/Remote): -/-\n" +
|
Direct: true
|
||||||
" Last connection update: 2001-01-01 01:01:01\n" +
|
ICE candidate (Local/Remote): -/-
|
||||||
"\n" +
|
ICE candidate endpoints (Local/Remote): -/-
|
||||||
" peer-2.awesome-domain.com:\n" +
|
Last connection update: 2001-01-01 01:01:01
|
||||||
" NetBird IP: 192.168.178.102\n" +
|
Last Wireguard handshake: 2001-01-01 01:01:02
|
||||||
" Public key: Pubkey2\n" +
|
Transfer status (received/sent) 200 B/100 B
|
||||||
" Status: Connected\n" +
|
|
||||||
" -- detail --\n" +
|
peer-2.awesome-domain.com:
|
||||||
" Connection type: Relayed\n" +
|
NetBird IP: 192.168.178.102
|
||||||
" Direct: false\n" +
|
Public key: Pubkey2
|
||||||
" ICE candidate (Local/Remote): relay/prflx\n" +
|
Status: Connected
|
||||||
" Last connection update: 2002-02-02 02:02:02\n" +
|
-- detail --
|
||||||
"\n" +
|
Connection type: Relayed
|
||||||
"Daemon version: 0.14.1\n" +
|
Direct: false
|
||||||
"CLI version: development\n" +
|
ICE candidate (Local/Remote): relay/prflx
|
||||||
"Management: Connected to my-awesome-management.com:443\n" +
|
ICE candidate endpoints (Local/Remote): 10.0.0.1:10001/10.0.10.1:10002
|
||||||
"Signal: Connected to my-awesome-signal.com:443\n" +
|
Last connection update: 2002-02-02 02:02:02
|
||||||
"FQDN: some-localhost.awesome-domain.com\n" +
|
Last Wireguard handshake: 2002-02-02 02:02:03
|
||||||
"NetBird IP: 192.168.178.100/16\n" +
|
Transfer status (received/sent) 2.0 KiB/1000 B
|
||||||
"Interface type: Kernel\n" +
|
|
||||||
"Peers count: 2/2 Connected\n"
|
Daemon version: 0.14.1
|
||||||
|
CLI version: development
|
||||||
|
Management: Connected to my-awesome-management.com:443
|
||||||
|
Signal: Connected to my-awesome-signal.com:443
|
||||||
|
Relays:
|
||||||
|
[stun:my-awesome-stun.com:3478] is Available
|
||||||
|
[turns:my-awesome-turn.com:443?transport=tcp] is Unavailable, reason: context: deadline exceeded
|
||||||
|
FQDN: some-localhost.awesome-domain.com
|
||||||
|
NetBird IP: 192.168.178.100/16
|
||||||
|
Interface type: Kernel
|
||||||
|
Peers count: 2/2 Connected
|
||||||
|
`
|
||||||
|
|
||||||
assert.Equal(t, expectedDetail, detail)
|
assert.Equal(t, expectedDetail, detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsingToShortVersion(t *testing.T) {
|
func TestParsingToShortVersion(t *testing.T) {
|
||||||
shortVersion := parseGeneralSummary(overview, false)
|
shortVersion := parseGeneralSummary(overview, false, false)
|
||||||
|
|
||||||
expectedString := "Daemon version: 0.14.1\n" +
|
expectedString :=
|
||||||
"CLI version: development\n" +
|
`Daemon version: 0.14.1
|
||||||
"Management: Connected\n" +
|
CLI version: development
|
||||||
"Signal: Connected\n" +
|
Management: Connected
|
||||||
"FQDN: some-localhost.awesome-domain.com\n" +
|
Signal: Connected
|
||||||
"NetBird IP: 192.168.178.100/16\n" +
|
Relays: 1/2 Available
|
||||||
"Interface type: Kernel\n" +
|
FQDN: some-localhost.awesome-domain.com
|
||||||
"Peers count: 2/2 Connected\n"
|
NetBird IP: 192.168.178.100/16
|
||||||
|
Interface type: Kernel
|
||||||
|
Peers count: 2/2 Connected
|
||||||
|
`
|
||||||
|
|
||||||
assert.Equal(t, expectedString, shortVersion)
|
assert.Equal(t, expectedString, shortVersion)
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,33 @@ import (
|
|||||||
|
|
||||||
// RunClient with main logic.
|
// RunClient with main logic.
|
||||||
func RunClient(ctx context.Context, config *Config, statusRecorder *peer.Status) error {
|
func RunClient(ctx context.Context, config *Config, statusRecorder *peer.Status) error {
|
||||||
return runClient(ctx, config, statusRecorder, MobileDependency{})
|
return runClient(ctx, config, statusRecorder, MobileDependency{}, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunClientWithProbes runs the client's main logic with probes attached
|
||||||
|
func RunClientWithProbes(
|
||||||
|
ctx context.Context,
|
||||||
|
config *Config,
|
||||||
|
statusRecorder *peer.Status,
|
||||||
|
mgmProbe *Probe,
|
||||||
|
signalProbe *Probe,
|
||||||
|
relayProbe *Probe,
|
||||||
|
wgProbe *Probe,
|
||||||
|
) error {
|
||||||
|
return runClient(ctx, config, statusRecorder, MobileDependency{}, mgmProbe, signalProbe, relayProbe, wgProbe)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunClientMobile with main logic on mobile system
|
// RunClientMobile with main logic on mobile system
|
||||||
func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.Status, tunAdapter iface.TunAdapter, iFaceDiscover stdnet.ExternalIFaceDiscover, networkChangeListener listener.NetworkChangeListener, dnsAddresses []string, dnsReadyListener dns.ReadyListener) error {
|
func RunClientMobile(
|
||||||
|
ctx context.Context,
|
||||||
|
config *Config,
|
||||||
|
statusRecorder *peer.Status,
|
||||||
|
tunAdapter iface.TunAdapter,
|
||||||
|
iFaceDiscover stdnet.ExternalIFaceDiscover,
|
||||||
|
networkChangeListener listener.NetworkChangeListener,
|
||||||
|
dnsAddresses []string,
|
||||||
|
dnsReadyListener dns.ReadyListener,
|
||||||
|
) error {
|
||||||
// in case of non Android os these variables will be nil
|
// in case of non Android os these variables will be nil
|
||||||
mobileDependency := MobileDependency{
|
mobileDependency := MobileDependency{
|
||||||
TunAdapter: tunAdapter,
|
TunAdapter: tunAdapter,
|
||||||
@ -40,19 +62,35 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S
|
|||||||
HostDNSAddresses: dnsAddresses,
|
HostDNSAddresses: dnsAddresses,
|
||||||
DnsReadyListener: dnsReadyListener,
|
DnsReadyListener: dnsReadyListener,
|
||||||
}
|
}
|
||||||
return runClient(ctx, config, statusRecorder, mobileDependency)
|
return runClient(ctx, config, statusRecorder, mobileDependency, nil, nil, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, networkChangeListener listener.NetworkChangeListener, dnsManager dns.IosDnsManager) error {
|
func RunClientiOS(
|
||||||
|
ctx context.Context,
|
||||||
|
config *Config,
|
||||||
|
statusRecorder *peer.Status,
|
||||||
|
fileDescriptor int32,
|
||||||
|
networkChangeListener listener.NetworkChangeListener,
|
||||||
|
dnsManager dns.IosDnsManager,
|
||||||
|
) error {
|
||||||
mobileDependency := MobileDependency{
|
mobileDependency := MobileDependency{
|
||||||
FileDescriptor: fileDescriptor,
|
FileDescriptor: fileDescriptor,
|
||||||
NetworkChangeListener: networkChangeListener,
|
NetworkChangeListener: networkChangeListener,
|
||||||
DnsManager: dnsManager,
|
DnsManager: dnsManager,
|
||||||
}
|
}
|
||||||
return runClient(ctx, config, statusRecorder, mobileDependency)
|
return runClient(ctx, config, statusRecorder, mobileDependency, nil, nil, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runClient(ctx context.Context, config *Config, statusRecorder *peer.Status, mobileDependency MobileDependency) error {
|
func runClient(
|
||||||
|
ctx context.Context,
|
||||||
|
config *Config,
|
||||||
|
statusRecorder *peer.Status,
|
||||||
|
mobileDependency MobileDependency,
|
||||||
|
mgmProbe *Probe,
|
||||||
|
signalProbe *Probe,
|
||||||
|
relayProbe *Probe,
|
||||||
|
wgProbe *Probe,
|
||||||
|
) error {
|
||||||
log.Infof("starting NetBird client version %s", version.NetbirdVersion())
|
log.Infof("starting NetBird client version %s", version.NetbirdVersion())
|
||||||
|
|
||||||
backOff := &backoff.ExponentialBackOff{
|
backOff := &backoff.ExponentialBackOff{
|
||||||
@ -103,7 +141,7 @@ func runClient(ctx context.Context, config *Config, statusRecorder *peer.Status,
|
|||||||
|
|
||||||
engineCtx, cancel := context.WithCancel(ctx)
|
engineCtx, cancel := context.WithCancel(ctx)
|
||||||
defer func() {
|
defer func() {
|
||||||
statusRecorder.MarkManagementDisconnected()
|
statusRecorder.MarkManagementDisconnected(state.err)
|
||||||
statusRecorder.CleanLocalPeerState()
|
statusRecorder.CleanLocalPeerState()
|
||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
@ -152,8 +190,10 @@ func runClient(ctx context.Context, config *Config, statusRecorder *peer.Status,
|
|||||||
|
|
||||||
statusRecorder.UpdateSignalAddress(signalURL)
|
statusRecorder.UpdateSignalAddress(signalURL)
|
||||||
|
|
||||||
statusRecorder.MarkSignalDisconnected()
|
statusRecorder.MarkSignalDisconnected(nil)
|
||||||
defer statusRecorder.MarkSignalDisconnected()
|
defer func() {
|
||||||
|
statusRecorder.MarkSignalDisconnected(state.err)
|
||||||
|
}()
|
||||||
|
|
||||||
// with the global Wiretrustee config in hand connect (just a connection, no stream yet) Signal
|
// with the global Wiretrustee config in hand connect (just a connection, no stream yet) Signal
|
||||||
signalClient, err := connectToSignal(engineCtx, loginResp.GetWiretrusteeConfig(), myPrivateKey)
|
signalClient, err := connectToSignal(engineCtx, loginResp.GetWiretrusteeConfig(), myPrivateKey)
|
||||||
@ -181,7 +221,7 @@ func runClient(ctx context.Context, config *Config, statusRecorder *peer.Status,
|
|||||||
return wrapErr(err)
|
return wrapErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
engine := NewEngine(engineCtx, cancel, signalClient, mgmClient, engineConfig, mobileDependency, statusRecorder)
|
engine := NewEngineWithProbes(engineCtx, cancel, signalClient, mgmClient, engineConfig, mobileDependency, statusRecorder, mgmProbe, signalProbe, relayProbe, wgProbe)
|
||||||
err = engine.Start()
|
err = engine.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error while starting Netbird Connection Engine: %s", err)
|
log.Errorf("error while starting Netbird Connection Engine: %s", err)
|
||||||
|
@ -59,6 +59,10 @@ func (w *mocWGIface) SetFilter(filter iface.PacketFilter) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *mocWGIface) GetStats(_ string) (iface.WGStats, error) {
|
||||||
|
return iface.WGStats{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
var zoneRecords = []nbdns.SimpleRecord{
|
var zoneRecords = []nbdns.SimpleRecord{
|
||||||
{
|
{
|
||||||
Name: "peera.netbird.cloud",
|
Name: "peera.netbird.cloud",
|
||||||
|
@ -11,4 +11,5 @@ type WGIface interface {
|
|||||||
IsUserspaceBind() bool
|
IsUserspaceBind() bool
|
||||||
GetFilter() iface.PacketFilter
|
GetFilter() iface.PacketFilter
|
||||||
GetDevice() *iface.DeviceWrapper
|
GetDevice() *iface.DeviceWrapper
|
||||||
|
GetStats(peerKey string) (iface.WGStats, error)
|
||||||
}
|
}
|
||||||
|
@ -9,5 +9,6 @@ type WGIface interface {
|
|||||||
IsUserspaceBind() bool
|
IsUserspaceBind() bool
|
||||||
GetFilter() iface.PacketFilter
|
GetFilter() iface.PacketFilter
|
||||||
GetDevice() *iface.DeviceWrapper
|
GetDevice() *iface.DeviceWrapper
|
||||||
|
GetStats(peerKey string) (iface.WGStats, error)
|
||||||
GetInterfaceGUIDString() (string, error)
|
GetInterfaceGUIDString() (string, error)
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/internal/acl"
|
"github.com/netbirdio/netbird/client/internal/acl"
|
||||||
"github.com/netbirdio/netbird/client/internal/dns"
|
"github.com/netbirdio/netbird/client/internal/dns"
|
||||||
"github.com/netbirdio/netbird/client/internal/peer"
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
|
"github.com/netbirdio/netbird/client/internal/relay"
|
||||||
"github.com/netbirdio/netbird/client/internal/rosenpass"
|
"github.com/netbirdio/netbird/client/internal/rosenpass"
|
||||||
"github.com/netbirdio/netbird/client/internal/routemanager"
|
"github.com/netbirdio/netbird/client/internal/routemanager"
|
||||||
"github.com/netbirdio/netbird/client/internal/wgproxy"
|
"github.com/netbirdio/netbird/client/internal/wgproxy"
|
||||||
@ -125,6 +126,11 @@ type Engine struct {
|
|||||||
acl acl.Manager
|
acl acl.Manager
|
||||||
|
|
||||||
dnsServer dns.Server
|
dnsServer dns.Server
|
||||||
|
|
||||||
|
mgmProbe *Probe
|
||||||
|
signalProbe *Probe
|
||||||
|
relayProbe *Probe
|
||||||
|
wgProbe *Probe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peer is an instance of the Connection Peer
|
// Peer is an instance of the Connection Peer
|
||||||
@ -135,11 +141,43 @@ type Peer struct {
|
|||||||
|
|
||||||
// NewEngine creates a new Connection Engine
|
// NewEngine creates a new Connection Engine
|
||||||
func NewEngine(
|
func NewEngine(
|
||||||
ctx context.Context, cancel context.CancelFunc,
|
ctx context.Context,
|
||||||
signalClient signal.Client, mgmClient mgm.Client,
|
cancel context.CancelFunc,
|
||||||
config *EngineConfig, mobileDep MobileDependency, statusRecorder *peer.Status,
|
signalClient signal.Client,
|
||||||
|
mgmClient mgm.Client,
|
||||||
|
config *EngineConfig,
|
||||||
|
mobileDep MobileDependency,
|
||||||
|
statusRecorder *peer.Status,
|
||||||
) *Engine {
|
) *Engine {
|
||||||
|
return NewEngineWithProbes(
|
||||||
|
ctx,
|
||||||
|
cancel,
|
||||||
|
signalClient,
|
||||||
|
mgmClient,
|
||||||
|
config,
|
||||||
|
mobileDep,
|
||||||
|
statusRecorder,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEngineWithProbes creates a new Connection Engine with probes attached
|
||||||
|
func NewEngineWithProbes(
|
||||||
|
ctx context.Context,
|
||||||
|
cancel context.CancelFunc,
|
||||||
|
signalClient signal.Client,
|
||||||
|
mgmClient mgm.Client,
|
||||||
|
config *EngineConfig,
|
||||||
|
mobileDep MobileDependency,
|
||||||
|
statusRecorder *peer.Status,
|
||||||
|
mgmProbe *Probe,
|
||||||
|
signalProbe *Probe,
|
||||||
|
relayProbe *Probe,
|
||||||
|
wgProbe *Probe,
|
||||||
|
) *Engine {
|
||||||
return &Engine{
|
return &Engine{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
@ -155,6 +193,10 @@ func NewEngine(
|
|||||||
sshServerFunc: nbssh.DefaultSSHServer,
|
sshServerFunc: nbssh.DefaultSSHServer,
|
||||||
statusRecorder: statusRecorder,
|
statusRecorder: statusRecorder,
|
||||||
wgProxyFactory: wgproxy.NewFactory(config.WgPort),
|
wgProxyFactory: wgproxy.NewFactory(config.WgPort),
|
||||||
|
mgmProbe: mgmProbe,
|
||||||
|
signalProbe: signalProbe,
|
||||||
|
relayProbe: relayProbe,
|
||||||
|
wgProbe: wgProbe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,6 +293,7 @@ func (e *Engine) Start() error {
|
|||||||
|
|
||||||
e.receiveSignalEvents()
|
e.receiveSignalEvents()
|
||||||
e.receiveManagementEvents()
|
e.receiveManagementEvents()
|
||||||
|
e.receiveProbeEvents()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -512,9 +555,7 @@ func (e *Engine) updateConfig(conf *mgmProto.PeerConfig) error {
|
|||||||
// E.g. when a new peer has been registered and we are allowed to connect to it.
|
// E.g. when a new peer has been registered and we are allowed to connect to it.
|
||||||
func (e *Engine) receiveManagementEvents() {
|
func (e *Engine) receiveManagementEvents() {
|
||||||
go func() {
|
go func() {
|
||||||
err := e.mgmClient.Sync(func(update *mgmProto.SyncResponse) error {
|
err := e.mgmClient.Sync(e.handleSync)
|
||||||
return e.handleSync(update)
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// happens if management is unavailable for a long time.
|
// happens if management is unavailable for a long time.
|
||||||
// We want to cancel the operation of the whole client
|
// We want to cancel the operation of the whole client
|
||||||
@ -1175,3 +1216,69 @@ func (e *Engine) getRosenpassAddr() string {
|
|||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Engine) receiveProbeEvents() {
|
||||||
|
if e.signalProbe != nil {
|
||||||
|
go e.signalProbe.Receive(e.ctx, func() bool {
|
||||||
|
healthy := e.signal.IsHealthy()
|
||||||
|
log.Debugf("received signal probe request, healthy: %t", healthy)
|
||||||
|
return healthy
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.mgmProbe != nil {
|
||||||
|
go e.mgmProbe.Receive(e.ctx, func() bool {
|
||||||
|
healthy := e.mgmClient.IsHealthy()
|
||||||
|
log.Debugf("received management probe request, healthy: %t", healthy)
|
||||||
|
return healthy
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.relayProbe != nil {
|
||||||
|
go e.relayProbe.Receive(e.ctx, func() bool {
|
||||||
|
healthy := true
|
||||||
|
|
||||||
|
results := append(e.probeSTUNs(), e.probeTURNs()...)
|
||||||
|
e.statusRecorder.UpdateRelayStates(results)
|
||||||
|
|
||||||
|
// A single failed server will result in a "failed" probe
|
||||||
|
for _, res := range results {
|
||||||
|
if res.Err != nil {
|
||||||
|
healthy = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("received relay probe request, healthy: %t", healthy)
|
||||||
|
return healthy
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.wgProbe != nil {
|
||||||
|
go e.wgProbe.Receive(e.ctx, func() bool {
|
||||||
|
log.Debug("received wg probe request")
|
||||||
|
|
||||||
|
for _, peer := range e.peerConns {
|
||||||
|
key := peer.GetKey()
|
||||||
|
wgStats, err := peer.GetConf().WgConfig.WgInterface.GetStats(key)
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("failed to get wg stats for peer %s: %s", key, err)
|
||||||
|
}
|
||||||
|
// wgStats could be zero value, in which case we just reset the stats
|
||||||
|
if err := e.statusRecorder.UpdateWireguardPeerState(key, wgStats); err != nil {
|
||||||
|
log.Debugf("failed to update wg stats for peer %s: %s", key, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) probeSTUNs() []relay.ProbeResult {
|
||||||
|
return relay.ProbeAll(e.ctx, relay.ProbeSTUN, e.STUNs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) probeTURNs() []relay.ProbeResult {
|
||||||
|
return relay.ProbeAll(e.ctx, relay.ProbeTURN, e.TURNs)
|
||||||
|
}
|
||||||
|
@ -408,12 +408,14 @@ func (conn *Conn) configureConnection(remoteConn net.Conn, remoteWgPort int, rem
|
|||||||
conn.status = StatusConnected
|
conn.status = StatusConnected
|
||||||
|
|
||||||
peerState := State{
|
peerState := State{
|
||||||
PubKey: conn.config.Key,
|
PubKey: conn.config.Key,
|
||||||
ConnStatus: conn.status,
|
ConnStatus: conn.status,
|
||||||
ConnStatusUpdate: time.Now(),
|
ConnStatusUpdate: time.Now(),
|
||||||
LocalIceCandidateType: pair.Local.Type().String(),
|
LocalIceCandidateType: pair.Local.Type().String(),
|
||||||
RemoteIceCandidateType: pair.Remote.Type().String(),
|
RemoteIceCandidateType: pair.Remote.Type().String(),
|
||||||
Direct: !isRelayCandidate(pair.Local),
|
LocalIceCandidateEndpoint: fmt.Sprintf("%s:%d", pair.Local.Address(), pair.Local.Port()),
|
||||||
|
RemoteIceCandidateEndpoint: fmt.Sprintf("%s:%d", pair.Remote.Address(), pair.Local.Port()),
|
||||||
|
Direct: !isRelayCandidate(pair.Local),
|
||||||
}
|
}
|
||||||
if pair.Local.Type() == ice.CandidateTypeRelay || pair.Remote.Type() == ice.CandidateTypeRelay {
|
if pair.Local.Type() == ice.CandidateTypeRelay || pair.Remote.Type() == ice.CandidateTypeRelay {
|
||||||
peerState.Relayed = true
|
peerState.Relayed = true
|
||||||
@ -500,6 +502,9 @@ func (conn *Conn) cleanup() error {
|
|||||||
// todo rethink status updates
|
// todo rethink status updates
|
||||||
log.Debugf("error while updating peer's %s state, err: %v", conn.config.Key, err)
|
log.Debugf("error while updating peer's %s state, err: %v", conn.config.Key, err)
|
||||||
}
|
}
|
||||||
|
if err := conn.statusRecorder.UpdateWireguardPeerState(conn.config.Key, iface.WGStats{}); err != nil {
|
||||||
|
log.Debugf("failed to reset wireguard stats for peer %s: %s", conn.config.Key, err)
|
||||||
|
}
|
||||||
|
|
||||||
log.Debugf("cleaned up connection to peer %s", conn.config.Key)
|
log.Debugf("cleaned up connection to peer %s", conn.config.Key)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
|
@ -4,19 +4,27 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/internal/relay"
|
||||||
|
"github.com/netbirdio/netbird/iface"
|
||||||
)
|
)
|
||||||
|
|
||||||
// State contains the latest state of a peer
|
// State contains the latest state of a peer
|
||||||
type State struct {
|
type State struct {
|
||||||
IP string
|
IP string
|
||||||
PubKey string
|
PubKey string
|
||||||
FQDN string
|
FQDN string
|
||||||
ConnStatus ConnStatus
|
ConnStatus ConnStatus
|
||||||
ConnStatusUpdate time.Time
|
ConnStatusUpdate time.Time
|
||||||
Relayed bool
|
Relayed bool
|
||||||
Direct bool
|
Direct bool
|
||||||
LocalIceCandidateType string
|
LocalIceCandidateType string
|
||||||
RemoteIceCandidateType string
|
RemoteIceCandidateType string
|
||||||
|
LocalIceCandidateEndpoint string
|
||||||
|
RemoteIceCandidateEndpoint string
|
||||||
|
LastWireguardHandshake time.Time
|
||||||
|
BytesTx int64
|
||||||
|
BytesRx int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalPeerState contains the latest state of the local peer
|
// LocalPeerState contains the latest state of the local peer
|
||||||
@ -31,12 +39,14 @@ type LocalPeerState struct {
|
|||||||
type SignalState struct {
|
type SignalState struct {
|
||||||
URL string
|
URL string
|
||||||
Connected bool
|
Connected bool
|
||||||
|
Error error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManagementState contains the latest state of a management connection
|
// ManagementState contains the latest state of a management connection
|
||||||
type ManagementState struct {
|
type ManagementState struct {
|
||||||
URL string
|
URL string
|
||||||
Connected bool
|
Connected bool
|
||||||
|
Error error
|
||||||
}
|
}
|
||||||
|
|
||||||
// FullStatus contains the full state held by the Status instance
|
// FullStatus contains the full state held by the Status instance
|
||||||
@ -45,15 +55,19 @@ type FullStatus struct {
|
|||||||
ManagementState ManagementState
|
ManagementState ManagementState
|
||||||
SignalState SignalState
|
SignalState SignalState
|
||||||
LocalPeerState LocalPeerState
|
LocalPeerState LocalPeerState
|
||||||
|
Relays []relay.ProbeResult
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status holds a state of peers, signal and management connections
|
// Status holds a state of peers, signal, management connections and relays
|
||||||
type Status struct {
|
type Status struct {
|
||||||
mux sync.Mutex
|
mux sync.Mutex
|
||||||
peers map[string]State
|
peers map[string]State
|
||||||
changeNotify map[string]chan struct{}
|
changeNotify map[string]chan struct{}
|
||||||
signalState bool
|
signalState bool
|
||||||
|
signalError error
|
||||||
managementState bool
|
managementState bool
|
||||||
|
managementError error
|
||||||
|
relayStates []relay.ProbeResult
|
||||||
localPeer LocalPeerState
|
localPeer LocalPeerState
|
||||||
offlinePeers []State
|
offlinePeers []State
|
||||||
mgmAddress string
|
mgmAddress string
|
||||||
@ -156,6 +170,8 @@ func (d *Status) UpdatePeerState(receivedState State) error {
|
|||||||
peerState.Relayed = receivedState.Relayed
|
peerState.Relayed = receivedState.Relayed
|
||||||
peerState.LocalIceCandidateType = receivedState.LocalIceCandidateType
|
peerState.LocalIceCandidateType = receivedState.LocalIceCandidateType
|
||||||
peerState.RemoteIceCandidateType = receivedState.RemoteIceCandidateType
|
peerState.RemoteIceCandidateType = receivedState.RemoteIceCandidateType
|
||||||
|
peerState.LocalIceCandidateEndpoint = receivedState.LocalIceCandidateEndpoint
|
||||||
|
peerState.RemoteIceCandidateEndpoint = receivedState.RemoteIceCandidateEndpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
d.peers[receivedState.PubKey] = peerState
|
d.peers[receivedState.PubKey] = peerState
|
||||||
@ -174,6 +190,25 @@ func (d *Status) UpdatePeerState(receivedState State) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateWireguardPeerState updates the wireguard bits of the peer state
|
||||||
|
func (d *Status) UpdateWireguardPeerState(pubKey string, wgStats iface.WGStats) error {
|
||||||
|
d.mux.Lock()
|
||||||
|
defer d.mux.Unlock()
|
||||||
|
|
||||||
|
peerState, ok := d.peers[pubKey]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("peer doesn't exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
peerState.LastWireguardHandshake = wgStats.LastHandshake
|
||||||
|
peerState.BytesRx = wgStats.RxBytes
|
||||||
|
peerState.BytesTx = wgStats.TxBytes
|
||||||
|
|
||||||
|
d.peers[pubKey] = peerState
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func shouldSkipNotify(received, curr State) bool {
|
func shouldSkipNotify(received, curr State) bool {
|
||||||
switch {
|
switch {
|
||||||
case received.ConnStatus == StatusConnecting:
|
case received.ConnStatus == StatusConnecting:
|
||||||
@ -248,12 +283,13 @@ func (d *Status) CleanLocalPeerState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarkManagementDisconnected sets ManagementState to disconnected
|
// MarkManagementDisconnected sets ManagementState to disconnected
|
||||||
func (d *Status) MarkManagementDisconnected() {
|
func (d *Status) MarkManagementDisconnected(err error) {
|
||||||
d.mux.Lock()
|
d.mux.Lock()
|
||||||
defer d.mux.Unlock()
|
defer d.mux.Unlock()
|
||||||
defer d.onConnectionChanged()
|
defer d.onConnectionChanged()
|
||||||
|
|
||||||
d.managementState = false
|
d.managementState = false
|
||||||
|
d.managementError = err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkManagementConnected sets ManagementState to connected
|
// MarkManagementConnected sets ManagementState to connected
|
||||||
@ -263,6 +299,7 @@ func (d *Status) MarkManagementConnected() {
|
|||||||
defer d.onConnectionChanged()
|
defer d.onConnectionChanged()
|
||||||
|
|
||||||
d.managementState = true
|
d.managementState = true
|
||||||
|
d.managementError = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateSignalAddress update the address of the signal server
|
// UpdateSignalAddress update the address of the signal server
|
||||||
@ -280,12 +317,13 @@ func (d *Status) UpdateManagementAddress(mgmAddress string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarkSignalDisconnected sets SignalState to disconnected
|
// MarkSignalDisconnected sets SignalState to disconnected
|
||||||
func (d *Status) MarkSignalDisconnected() {
|
func (d *Status) MarkSignalDisconnected(err error) {
|
||||||
d.mux.Lock()
|
d.mux.Lock()
|
||||||
defer d.mux.Unlock()
|
defer d.mux.Unlock()
|
||||||
defer d.onConnectionChanged()
|
defer d.onConnectionChanged()
|
||||||
|
|
||||||
d.signalState = false
|
d.signalState = false
|
||||||
|
d.signalError = err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkSignalConnected sets SignalState to connected
|
// MarkSignalConnected sets SignalState to connected
|
||||||
@ -295,6 +333,33 @@ func (d *Status) MarkSignalConnected() {
|
|||||||
defer d.onConnectionChanged()
|
defer d.onConnectionChanged()
|
||||||
|
|
||||||
d.signalState = true
|
d.signalState = true
|
||||||
|
d.signalError = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Status) UpdateRelayStates(relayResults []relay.ProbeResult) {
|
||||||
|
d.mux.Lock()
|
||||||
|
defer d.mux.Unlock()
|
||||||
|
d.relayStates = relayResults
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Status) GetManagementState() ManagementState {
|
||||||
|
return ManagementState{
|
||||||
|
d.mgmAddress,
|
||||||
|
d.managementState,
|
||||||
|
d.managementError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Status) GetSignalState() SignalState {
|
||||||
|
return SignalState{
|
||||||
|
d.signalAddress,
|
||||||
|
d.signalState,
|
||||||
|
d.signalError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Status) GetRelayStates() []relay.ProbeResult {
|
||||||
|
return d.relayStates
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFullStatus gets full status
|
// GetFullStatus gets full status
|
||||||
@ -303,15 +368,10 @@ func (d *Status) GetFullStatus() FullStatus {
|
|||||||
defer d.mux.Unlock()
|
defer d.mux.Unlock()
|
||||||
|
|
||||||
fullStatus := FullStatus{
|
fullStatus := FullStatus{
|
||||||
ManagementState: ManagementState{
|
ManagementState: d.GetManagementState(),
|
||||||
d.mgmAddress,
|
SignalState: d.GetSignalState(),
|
||||||
d.managementState,
|
LocalPeerState: d.localPeer,
|
||||||
},
|
Relays: d.GetRelayStates(),
|
||||||
SignalState: SignalState{
|
|
||||||
d.signalAddress,
|
|
||||||
d.signalState,
|
|
||||||
},
|
|
||||||
LocalPeerState: d.localPeer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, status := range d.peers {
|
for _, status := range d.peers {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package peer
|
package peer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -152,9 +153,10 @@ func TestUpdateSignalState(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
connected bool
|
connected bool
|
||||||
want bool
|
want bool
|
||||||
|
err error
|
||||||
}{
|
}{
|
||||||
{"should mark as connected", true, true},
|
{"should mark as connected", true, true, nil},
|
||||||
{"should mark as disconnected", false, false},
|
{"should mark as disconnected", false, false, errors.New("test")},
|
||||||
}
|
}
|
||||||
|
|
||||||
status := NewRecorder("https://mgm")
|
status := NewRecorder("https://mgm")
|
||||||
@ -165,9 +167,10 @@ func TestUpdateSignalState(t *testing.T) {
|
|||||||
if test.connected {
|
if test.connected {
|
||||||
status.MarkSignalConnected()
|
status.MarkSignalConnected()
|
||||||
} else {
|
} else {
|
||||||
status.MarkSignalDisconnected()
|
status.MarkSignalDisconnected(test.err)
|
||||||
}
|
}
|
||||||
assert.Equal(t, test.want, status.signalState, "signal status should be equal")
|
assert.Equal(t, test.want, status.signalState, "signal status should be equal")
|
||||||
|
assert.Equal(t, test.err, status.signalError)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,9 +181,10 @@ func TestUpdateManagementState(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
connected bool
|
connected bool
|
||||||
want bool
|
want bool
|
||||||
|
err error
|
||||||
}{
|
}{
|
||||||
{"should mark as connected", true, true},
|
{"should mark as connected", true, true, nil},
|
||||||
{"should mark as disconnected", false, false},
|
{"should mark as disconnected", false, false, errors.New("test")},
|
||||||
}
|
}
|
||||||
|
|
||||||
status := NewRecorder(url)
|
status := NewRecorder(url)
|
||||||
@ -190,9 +194,10 @@ func TestUpdateManagementState(t *testing.T) {
|
|||||||
if test.connected {
|
if test.connected {
|
||||||
status.MarkManagementConnected()
|
status.MarkManagementConnected()
|
||||||
} else {
|
} else {
|
||||||
status.MarkManagementDisconnected()
|
status.MarkManagementDisconnected(test.err)
|
||||||
}
|
}
|
||||||
assert.Equal(t, test.want, status.managementState, "signalState status should be equal")
|
assert.Equal(t, test.want, status.managementState, "signalState status should be equal")
|
||||||
|
assert.Equal(t, test.err, status.managementError)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
51
client/internal/probe.go
Normal file
51
client/internal/probe.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// Probe allows to run on-demand callbacks from different code locations.
|
||||||
|
// Pass the probe to a receiving and a sending end. The receiving end starts listening
|
||||||
|
// to requests with Receive and executes a callback when the sending end requests it
|
||||||
|
// by calling Probe.
|
||||||
|
type Probe struct {
|
||||||
|
request chan struct{}
|
||||||
|
result chan bool
|
||||||
|
ready bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProbe returns a new initialized probe.
|
||||||
|
func NewProbe() *Probe {
|
||||||
|
return &Probe{
|
||||||
|
request: make(chan struct{}),
|
||||||
|
result: make(chan bool),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Probe requests the callback to be run and returns a bool indicating success.
|
||||||
|
// It always returns true as long as the receiver is not ready.
|
||||||
|
func (p *Probe) Probe() bool {
|
||||||
|
if !p.ready {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
p.request <- struct{}{}
|
||||||
|
return <-p.result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive starts listening for probe requests. On such a request it runs the supplied
|
||||||
|
// callback func which must return a bool indicating success.
|
||||||
|
// Blocks until the passed context is cancelled.
|
||||||
|
func (p *Probe) Receive(ctx context.Context, callback func() bool) {
|
||||||
|
p.ready = true
|
||||||
|
defer func() {
|
||||||
|
p.ready = false
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-p.request:
|
||||||
|
p.result <- callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
171
client/internal/relay/relay.go
Normal file
171
client/internal/relay/relay.go
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package relay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pion/stun/v2"
|
||||||
|
"github.com/pion/turn/v3"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProbeResult holds the info about the result of a relay probe request
|
||||||
|
type ProbeResult struct {
|
||||||
|
URI *stun.URI
|
||||||
|
Err error
|
||||||
|
Addr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProbeSTUN tries binding to the given STUN uri and acquiring an address
|
||||||
|
func ProbeSTUN(ctx context.Context, uri *stun.URI) (addr string, probeErr error) {
|
||||||
|
defer func() {
|
||||||
|
if probeErr != nil {
|
||||||
|
log.Debugf("stun probe error from %s: %s", uri, probeErr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
client, err := stun.DialURI(uri, &stun.DialConfig{})
|
||||||
|
if err != nil {
|
||||||
|
probeErr = fmt.Errorf("dial: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := client.Close(); err != nil && probeErr == nil {
|
||||||
|
probeErr = fmt.Errorf("close: %w", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
if err = client.Start(stun.MustBuild(stun.TransactionID, stun.BindingRequest), func(res stun.Event) {
|
||||||
|
if res.Error != nil {
|
||||||
|
probeErr = fmt.Errorf("request: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var xorAddr stun.XORMappedAddress
|
||||||
|
if getErr := xorAddr.GetFrom(res.Message); getErr != nil {
|
||||||
|
probeErr = fmt.Errorf("get xor addr: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("stun probe received address from %s: %s", uri, xorAddr)
|
||||||
|
addr = xorAddr.String()
|
||||||
|
|
||||||
|
done <- struct{}{}
|
||||||
|
}); err != nil {
|
||||||
|
probeErr = fmt.Errorf("client: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
probeErr = fmt.Errorf("stun request: %w", ctx.Err())
|
||||||
|
return
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProbeTURN tries allocating a session from the given TURN URI
|
||||||
|
func ProbeTURN(ctx context.Context, uri *stun.URI) (addr string, probeErr error) {
|
||||||
|
defer func() {
|
||||||
|
if probeErr != nil {
|
||||||
|
log.Debugf("turn probe error from %s: %s", uri, probeErr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
turnServerAddr := fmt.Sprintf("%s:%d", uri.Host, uri.Port)
|
||||||
|
|
||||||
|
var conn net.PacketConn
|
||||||
|
switch uri.Proto {
|
||||||
|
case stun.ProtoTypeUDP:
|
||||||
|
var err error
|
||||||
|
conn, err = net.ListenPacket("udp", "")
|
||||||
|
if err != nil {
|
||||||
|
probeErr = fmt.Errorf("listen: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case stun.ProtoTypeTCP:
|
||||||
|
dialer := net.Dialer{}
|
||||||
|
tcpConn, err := dialer.DialContext(ctx, "tcp", turnServerAddr)
|
||||||
|
if err != nil {
|
||||||
|
probeErr = fmt.Errorf("dial: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn = turn.NewSTUNConn(tcpConn)
|
||||||
|
default:
|
||||||
|
probeErr = fmt.Errorf("conn: unknown proto: %s", uri.Proto)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := conn.Close(); err != nil && probeErr == nil {
|
||||||
|
probeErr = fmt.Errorf("conn close: %w", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
cfg := &turn.ClientConfig{
|
||||||
|
STUNServerAddr: turnServerAddr,
|
||||||
|
TURNServerAddr: turnServerAddr,
|
||||||
|
Conn: conn,
|
||||||
|
Username: uri.Username,
|
||||||
|
Password: uri.Password,
|
||||||
|
}
|
||||||
|
client, err := turn.NewClient(cfg)
|
||||||
|
if err != nil {
|
||||||
|
probeErr = fmt.Errorf("create client: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
if err := client.Listen(); err != nil {
|
||||||
|
probeErr = fmt.Errorf("client listen: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
relayConn, err := client.Allocate()
|
||||||
|
if err != nil {
|
||||||
|
probeErr = fmt.Errorf("allocate: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := relayConn.Close(); err != nil && probeErr == nil {
|
||||||
|
probeErr = fmt.Errorf("close relay conn: %w", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.Debugf("turn probe relay address from %s: %s", uri, relayConn.LocalAddr())
|
||||||
|
|
||||||
|
return relayConn.LocalAddr().String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProbeAll probes all given servers asynchronously and returns the results
|
||||||
|
func ProbeAll(
|
||||||
|
ctx context.Context,
|
||||||
|
fn func(ctx context.Context, uri *stun.URI) (addr string, probeErr error),
|
||||||
|
relays []*stun.URI,
|
||||||
|
) []ProbeResult {
|
||||||
|
results := make([]ProbeResult, len(relays))
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i, uri := range relays {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func(res *ProbeResult, stunURI *stun.URI) {
|
||||||
|
defer wg.Done()
|
||||||
|
res.URI = stunURI
|
||||||
|
res.Addr, res.Err = fn(ctx, stunURI)
|
||||||
|
}(&results[i], uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.26.0
|
// protoc-gen-go v1.26.0
|
||||||
// protoc v4.24.3
|
// protoc v3.21.9
|
||||||
// source: daemon.proto
|
// source: daemon.proto
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
@ -733,15 +733,20 @@ type PeerState struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
IP string `protobuf:"bytes,1,opt,name=IP,proto3" json:"IP,omitempty"`
|
IP string `protobuf:"bytes,1,opt,name=IP,proto3" json:"IP,omitempty"`
|
||||||
PubKey string `protobuf:"bytes,2,opt,name=pubKey,proto3" json:"pubKey,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"`
|
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"`
|
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"`
|
Relayed bool `protobuf:"varint,5,opt,name=relayed,proto3" json:"relayed,omitempty"`
|
||||||
Direct bool `protobuf:"varint,6,opt,name=direct,proto3" json:"direct,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"`
|
LocalIceCandidateType string `protobuf:"bytes,7,opt,name=localIceCandidateType,proto3" json:"localIceCandidateType,omitempty"`
|
||||||
RemoteIceCandidateType string `protobuf:"bytes,8,opt,name=remoteIceCandidateType,proto3" json:"remoteIceCandidateType,omitempty"`
|
RemoteIceCandidateType string `protobuf:"bytes,8,opt,name=remoteIceCandidateType,proto3" json:"remoteIceCandidateType,omitempty"`
|
||||||
Fqdn string `protobuf:"bytes,9,opt,name=fqdn,proto3" json:"fqdn,omitempty"`
|
Fqdn string `protobuf:"bytes,9,opt,name=fqdn,proto3" json:"fqdn,omitempty"`
|
||||||
|
LocalIceCandidateEndpoint string `protobuf:"bytes,10,opt,name=localIceCandidateEndpoint,proto3" json:"localIceCandidateEndpoint,omitempty"`
|
||||||
|
RemoteIceCandidateEndpoint string `protobuf:"bytes,11,opt,name=remoteIceCandidateEndpoint,proto3" json:"remoteIceCandidateEndpoint,omitempty"`
|
||||||
|
LastWireguardHandshake *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=lastWireguardHandshake,proto3" json:"lastWireguardHandshake,omitempty"`
|
||||||
|
BytesRx int64 `protobuf:"varint,13,opt,name=bytesRx,proto3" json:"bytesRx,omitempty"`
|
||||||
|
BytesTx int64 `protobuf:"varint,14,opt,name=bytesTx,proto3" json:"bytesTx,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PeerState) Reset() {
|
func (x *PeerState) Reset() {
|
||||||
@ -839,6 +844,41 @@ func (x *PeerState) GetFqdn() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *PeerState) GetLocalIceCandidateEndpoint() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.LocalIceCandidateEndpoint
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PeerState) GetRemoteIceCandidateEndpoint() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.RemoteIceCandidateEndpoint
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PeerState) GetLastWireguardHandshake() *timestamppb.Timestamp {
|
||||||
|
if x != nil {
|
||||||
|
return x.LastWireguardHandshake
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PeerState) GetBytesRx() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.BytesRx
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PeerState) GetBytesTx() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.BytesTx
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// LocalPeerState contains the latest state of the local peer
|
// LocalPeerState contains the latest state of the local peer
|
||||||
type LocalPeerState struct {
|
type LocalPeerState struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
@ -919,6 +959,7 @@ type SignalState struct {
|
|||||||
|
|
||||||
URL string `protobuf:"bytes,1,opt,name=URL,proto3" json:"URL,omitempty"`
|
URL string `protobuf:"bytes,1,opt,name=URL,proto3" json:"URL,omitempty"`
|
||||||
Connected bool `protobuf:"varint,2,opt,name=connected,proto3" json:"connected,omitempty"`
|
Connected bool `protobuf:"varint,2,opt,name=connected,proto3" json:"connected,omitempty"`
|
||||||
|
Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SignalState) Reset() {
|
func (x *SignalState) Reset() {
|
||||||
@ -967,6 +1008,13 @@ func (x *SignalState) GetConnected() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *SignalState) GetError() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Error
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// ManagementState contains the latest state of a management connection
|
// ManagementState contains the latest state of a management connection
|
||||||
type ManagementState struct {
|
type ManagementState struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
@ -975,6 +1023,7 @@ type ManagementState struct {
|
|||||||
|
|
||||||
URL string `protobuf:"bytes,1,opt,name=URL,proto3" json:"URL,omitempty"`
|
URL string `protobuf:"bytes,1,opt,name=URL,proto3" json:"URL,omitempty"`
|
||||||
Connected bool `protobuf:"varint,2,opt,name=connected,proto3" json:"connected,omitempty"`
|
Connected bool `protobuf:"varint,2,opt,name=connected,proto3" json:"connected,omitempty"`
|
||||||
|
Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ManagementState) Reset() {
|
func (x *ManagementState) Reset() {
|
||||||
@ -1023,6 +1072,77 @@ func (x *ManagementState) GetConnected() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *ManagementState) GetError() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Error
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// RelayState contains the latest state of the relay
|
||||||
|
type RelayState struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
URI string `protobuf:"bytes,1,opt,name=URI,proto3" json:"URI,omitempty"`
|
||||||
|
Available bool `protobuf:"varint,2,opt,name=available,proto3" json:"available,omitempty"`
|
||||||
|
Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RelayState) Reset() {
|
||||||
|
*x = RelayState{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_daemon_proto_msgTypes[16]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RelayState) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*RelayState) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *RelayState) 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 RelayState.ProtoReflect.Descriptor instead.
|
||||||
|
func (*RelayState) Descriptor() ([]byte, []int) {
|
||||||
|
return file_daemon_proto_rawDescGZIP(), []int{16}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RelayState) GetURI() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.URI
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RelayState) GetAvailable() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Available
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RelayState) GetError() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Error
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// FullStatus contains the full state held by the Status instance
|
// FullStatus contains the full state held by the Status instance
|
||||||
type FullStatus struct {
|
type FullStatus struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
@ -1033,12 +1153,13 @@ type FullStatus struct {
|
|||||||
SignalState *SignalState `protobuf:"bytes,2,opt,name=signalState,proto3" json:"signalState,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"`
|
LocalPeerState *LocalPeerState `protobuf:"bytes,3,opt,name=localPeerState,proto3" json:"localPeerState,omitempty"`
|
||||||
Peers []*PeerState `protobuf:"bytes,4,rep,name=peers,proto3" json:"peers,omitempty"`
|
Peers []*PeerState `protobuf:"bytes,4,rep,name=peers,proto3" json:"peers,omitempty"`
|
||||||
|
Relays []*RelayState `protobuf:"bytes,5,rep,name=relays,proto3" json:"relays,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *FullStatus) Reset() {
|
func (x *FullStatus) Reset() {
|
||||||
*x = FullStatus{}
|
*x = FullStatus{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_daemon_proto_msgTypes[16]
|
mi := &file_daemon_proto_msgTypes[17]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -1051,7 +1172,7 @@ func (x *FullStatus) String() string {
|
|||||||
func (*FullStatus) ProtoMessage() {}
|
func (*FullStatus) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *FullStatus) ProtoReflect() protoreflect.Message {
|
func (x *FullStatus) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_daemon_proto_msgTypes[16]
|
mi := &file_daemon_proto_msgTypes[17]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -1064,7 +1185,7 @@ func (x *FullStatus) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use FullStatus.ProtoReflect.Descriptor instead.
|
// Deprecated: Use FullStatus.ProtoReflect.Descriptor instead.
|
||||||
func (*FullStatus) Descriptor() ([]byte, []int) {
|
func (*FullStatus) Descriptor() ([]byte, []int) {
|
||||||
return file_daemon_proto_rawDescGZIP(), []int{16}
|
return file_daemon_proto_rawDescGZIP(), []int{17}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *FullStatus) GetManagementState() *ManagementState {
|
func (x *FullStatus) GetManagementState() *ManagementState {
|
||||||
@ -1095,6 +1216,13 @@ func (x *FullStatus) GetPeers() []*PeerState {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *FullStatus) GetRelays() []*RelayState {
|
||||||
|
if x != nil {
|
||||||
|
return x.Relays
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var File_daemon_proto protoreflect.FileDescriptor
|
var File_daemon_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_daemon_proto_rawDesc = []byte{
|
var file_daemon_proto_rawDesc = []byte{
|
||||||
@ -1190,7 +1318,7 @@ var file_daemon_proto_rawDesc = []byte{
|
|||||||
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64,
|
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,
|
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,
|
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x52, 0x4c, 0x22,
|
||||||
0xcf, 0x02, 0x0a, 0x09, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a,
|
0xd5, 0x04, 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,
|
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,
|
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,
|
0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x53, 0x74, 0x61,
|
||||||
@ -1211,62 +1339,89 @@ var file_daemon_proto_rawDesc = []byte{
|
|||||||
0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x63, 0x65,
|
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, 0x12, 0x12, 0x0a,
|
0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a,
|
||||||
0x04, 0x66, 0x71, 0x64, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x64,
|
0x04, 0x66, 0x71, 0x64, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x64,
|
||||||
0x6e, 0x22, 0x76, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74,
|
0x6e, 0x12, 0x3c, 0x0a, 0x19, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x63, 0x65, 0x43, 0x61, 0x6e,
|
||||||
0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x50, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x0a,
|
||||||
0x02, 0x49, 0x50, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x63, 0x65, 0x43, 0x61,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x6b,
|
0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12,
|
||||||
0x65, 0x72, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x03,
|
0x3e, 0x0a, 0x1a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x64,
|
||||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x74, 0x65,
|
0x69, 0x64, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x0b, 0x20,
|
||||||
0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x64, 0x6e, 0x18, 0x04, 0x20,
|
0x01, 0x28, 0x09, 0x52, 0x1a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x63, 0x65, 0x43, 0x61,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x64, 0x6e, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x69, 0x67,
|
0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12,
|
||||||
0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x18,
|
0x52, 0x0a, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x57, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x52, 0x4c, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f,
|
0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63,
|
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x41, 0x0a, 0x0f, 0x4d, 0x61, 0x6e, 0x61,
|
0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x16, 0x6c, 0x61, 0x73,
|
||||||
0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x55,
|
0x74, 0x57, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68,
|
||||||
0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x52, 0x4c, 0x12, 0x1c, 0x0a,
|
0x61, 0x6b, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x79, 0x74, 0x65, 0x73, 0x52, 0x78, 0x18, 0x0d,
|
||||||
0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
|
0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x79, 0x74, 0x65, 0x73, 0x52, 0x78, 0x12, 0x18, 0x0a,
|
||||||
0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0xef, 0x01, 0x0a, 0x0a,
|
0x07, 0x62, 0x79, 0x74, 0x65, 0x73, 0x54, 0x78, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
|
||||||
0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x41, 0x0a, 0x0f, 0x6d, 0x61,
|
0x62, 0x79, 0x74, 0x65, 0x73, 0x54, 0x78, 0x22, 0x76, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
|
||||||
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20,
|
0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x50, 0x18,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x61, 0x6e,
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x50, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62,
|
||||||
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0f, 0x6d, 0x61,
|
0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65,
|
||||||
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a,
|
0x79, 0x12, 0x28, 0x0a, 0x0f, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72,
|
||||||
0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01,
|
0x66, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6b, 0x65, 0x72, 0x6e,
|
||||||
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x69, 0x67, 0x6e,
|
0x65, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66,
|
||||||
0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53,
|
0x71, 0x64, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x64, 0x6e, 0x22,
|
||||||
0x74, 0x61, 0x74, 0x65, 0x12, 0x3e, 0x0a, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x65, 0x65,
|
0x53, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10,
|
||||||
0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64,
|
0x0a, 0x03, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x52, 0x4c,
|
||||||
0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x65, 0x65, 0x72, 0x53,
|
0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20,
|
||||||
0x74, 0x61, 0x74, 0x65, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x65, 0x65, 0x72, 0x53,
|
0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x14,
|
||||||
0x74, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20,
|
0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65,
|
||||||
0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x65, 0x65,
|
0x72, 0x72, 0x6f, 0x72, 0x22, 0x57, 0x0a, 0x0f, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65,
|
||||||
0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x32, 0xf7, 0x02,
|
0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x18, 0x01,
|
||||||
0x0a, 0x0d, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x52, 0x4c, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e,
|
||||||
0x36, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x14, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f,
|
0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f,
|
||||||
0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15,
|
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||||
0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73,
|
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x52, 0x0a,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0c, 0x57, 0x61, 0x69, 0x74, 0x53,
|
0x0a, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x55,
|
||||||
0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e,
|
0x52, 0x49, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x52, 0x49, 0x12, 0x1c, 0x0a,
|
||||||
0x2e, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71,
|
0x09, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
|
||||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61,
|
0x52, 0x09, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65,
|
||||||
0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f,
|
||||||
0x73, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x02, 0x55, 0x70, 0x12, 0x11, 0x2e, 0x64, 0x61, 0x65,
|
0x72, 0x22, 0x9b, 0x02, 0x0a, 0x0a, 0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||||
0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e,
|
0x12, 0x41, 0x0a, 0x0f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74,
|
||||||
0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x64, 0x61, 0x65, 0x6d,
|
||||||
0x65, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x15, 0x2e,
|
0x6f, 0x6e, 0x2e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61,
|
||||||
0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71,
|
0x74, 0x65, 0x52, 0x0f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74,
|
||||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74,
|
0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61,
|
||||||
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33,
|
0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f,
|
||||||
0x0a, 0x04, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x13, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e,
|
0x6e, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x73,
|
||||||
0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x64, 0x61,
|
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3e, 0x0a, 0x0e, 0x6c, 0x6f,
|
||||||
0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
0x63, 0x61, 0x6c, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01,
|
||||||
0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x63, 0x61,
|
||||||
0x12, 0x18, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e,
|
0x6c, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61,
|
||||||
0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x64, 0x61, 0x65,
|
0x6c, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x05, 0x70, 0x65,
|
||||||
0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73,
|
0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, 0x61, 0x65, 0x6d,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
0x6f, 0x6e, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x70, 0x65,
|
||||||
0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x06, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x73, 0x18, 0x05, 0x20,
|
||||||
|
0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x6c,
|
||||||
|
0x61, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, 0x72, 0x65, 0x6c, 0x61, 0x79, 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 (
|
var (
|
||||||
@ -1281,7 +1436,7 @@ func file_daemon_proto_rawDescGZIP() []byte {
|
|||||||
return file_daemon_proto_rawDescData
|
return file_daemon_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
|
var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
|
||||||
var file_daemon_proto_goTypes = []interface{}{
|
var file_daemon_proto_goTypes = []interface{}{
|
||||||
(*LoginRequest)(nil), // 0: daemon.LoginRequest
|
(*LoginRequest)(nil), // 0: daemon.LoginRequest
|
||||||
(*LoginResponse)(nil), // 1: daemon.LoginResponse
|
(*LoginResponse)(nil), // 1: daemon.LoginResponse
|
||||||
@ -1299,33 +1454,36 @@ var file_daemon_proto_goTypes = []interface{}{
|
|||||||
(*LocalPeerState)(nil), // 13: daemon.LocalPeerState
|
(*LocalPeerState)(nil), // 13: daemon.LocalPeerState
|
||||||
(*SignalState)(nil), // 14: daemon.SignalState
|
(*SignalState)(nil), // 14: daemon.SignalState
|
||||||
(*ManagementState)(nil), // 15: daemon.ManagementState
|
(*ManagementState)(nil), // 15: daemon.ManagementState
|
||||||
(*FullStatus)(nil), // 16: daemon.FullStatus
|
(*RelayState)(nil), // 16: daemon.RelayState
|
||||||
(*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp
|
(*FullStatus)(nil), // 17: daemon.FullStatus
|
||||||
|
(*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp
|
||||||
}
|
}
|
||||||
var file_daemon_proto_depIdxs = []int32{
|
var file_daemon_proto_depIdxs = []int32{
|
||||||
16, // 0: daemon.StatusResponse.fullStatus:type_name -> daemon.FullStatus
|
17, // 0: daemon.StatusResponse.fullStatus:type_name -> daemon.FullStatus
|
||||||
17, // 1: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp
|
18, // 1: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp
|
||||||
15, // 2: daemon.FullStatus.managementState:type_name -> daemon.ManagementState
|
18, // 2: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp
|
||||||
14, // 3: daemon.FullStatus.signalState:type_name -> daemon.SignalState
|
15, // 3: daemon.FullStatus.managementState:type_name -> daemon.ManagementState
|
||||||
13, // 4: daemon.FullStatus.localPeerState:type_name -> daemon.LocalPeerState
|
14, // 4: daemon.FullStatus.signalState:type_name -> daemon.SignalState
|
||||||
12, // 5: daemon.FullStatus.peers:type_name -> daemon.PeerState
|
13, // 5: daemon.FullStatus.localPeerState:type_name -> daemon.LocalPeerState
|
||||||
0, // 6: daemon.DaemonService.Login:input_type -> daemon.LoginRequest
|
12, // 6: daemon.FullStatus.peers:type_name -> daemon.PeerState
|
||||||
2, // 7: daemon.DaemonService.WaitSSOLogin:input_type -> daemon.WaitSSOLoginRequest
|
16, // 7: daemon.FullStatus.relays:type_name -> daemon.RelayState
|
||||||
4, // 8: daemon.DaemonService.Up:input_type -> daemon.UpRequest
|
0, // 8: daemon.DaemonService.Login:input_type -> daemon.LoginRequest
|
||||||
6, // 9: daemon.DaemonService.Status:input_type -> daemon.StatusRequest
|
2, // 9: daemon.DaemonService.WaitSSOLogin:input_type -> daemon.WaitSSOLoginRequest
|
||||||
8, // 10: daemon.DaemonService.Down:input_type -> daemon.DownRequest
|
4, // 10: daemon.DaemonService.Up:input_type -> daemon.UpRequest
|
||||||
10, // 11: daemon.DaemonService.GetConfig:input_type -> daemon.GetConfigRequest
|
6, // 11: daemon.DaemonService.Status:input_type -> daemon.StatusRequest
|
||||||
1, // 12: daemon.DaemonService.Login:output_type -> daemon.LoginResponse
|
8, // 12: daemon.DaemonService.Down:input_type -> daemon.DownRequest
|
||||||
3, // 13: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse
|
10, // 13: daemon.DaemonService.GetConfig:input_type -> daemon.GetConfigRequest
|
||||||
5, // 14: daemon.DaemonService.Up:output_type -> daemon.UpResponse
|
1, // 14: daemon.DaemonService.Login:output_type -> daemon.LoginResponse
|
||||||
7, // 15: daemon.DaemonService.Status:output_type -> daemon.StatusResponse
|
3, // 15: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse
|
||||||
9, // 16: daemon.DaemonService.Down:output_type -> daemon.DownResponse
|
5, // 16: daemon.DaemonService.Up:output_type -> daemon.UpResponse
|
||||||
11, // 17: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse
|
7, // 17: daemon.DaemonService.Status:output_type -> daemon.StatusResponse
|
||||||
12, // [12:18] is the sub-list for method output_type
|
9, // 18: daemon.DaemonService.Down:output_type -> daemon.DownResponse
|
||||||
6, // [6:12] is the sub-list for method input_type
|
11, // 19: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse
|
||||||
6, // [6:6] is the sub-list for extension type_name
|
14, // [14:20] is the sub-list for method output_type
|
||||||
6, // [6:6] is the sub-list for extension extendee
|
8, // [8:14] is the sub-list for method input_type
|
||||||
0, // [0:6] is the sub-list for field type_name
|
8, // [8:8] is the sub-list for extension type_name
|
||||||
|
8, // [8:8] is the sub-list for extension extendee
|
||||||
|
0, // [0:8] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_daemon_proto_init() }
|
func init() { file_daemon_proto_init() }
|
||||||
@ -1527,6 +1685,18 @@ func file_daemon_proto_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_daemon_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
|
file_daemon_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*RelayState); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_daemon_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*FullStatus); i {
|
switch v := v.(*FullStatus); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@ -1546,7 +1716,7 @@ func file_daemon_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_daemon_proto_rawDesc,
|
RawDescriptor: file_daemon_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 17,
|
NumMessages: 18,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
@ -127,15 +127,20 @@ message PeerState {
|
|||||||
bool relayed = 5;
|
bool relayed = 5;
|
||||||
bool direct = 6;
|
bool direct = 6;
|
||||||
string localIceCandidateType = 7;
|
string localIceCandidateType = 7;
|
||||||
string remoteIceCandidateType =8;
|
string remoteIceCandidateType = 8;
|
||||||
string fqdn = 9;
|
string fqdn = 9;
|
||||||
|
string localIceCandidateEndpoint = 10;
|
||||||
|
string remoteIceCandidateEndpoint = 11;
|
||||||
|
google.protobuf.Timestamp lastWireguardHandshake = 12;
|
||||||
|
int64 bytesRx = 13;
|
||||||
|
int64 bytesTx = 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalPeerState contains the latest state of the local peer
|
// LocalPeerState contains the latest state of the local peer
|
||||||
message LocalPeerState {
|
message LocalPeerState {
|
||||||
string IP = 1;
|
string IP = 1;
|
||||||
string pubKey = 2;
|
string pubKey = 2;
|
||||||
bool kernelInterface =3;
|
bool kernelInterface = 3;
|
||||||
string fqdn = 4;
|
string fqdn = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,17 +148,28 @@ message LocalPeerState {
|
|||||||
message SignalState {
|
message SignalState {
|
||||||
string URL = 1;
|
string URL = 1;
|
||||||
bool connected = 2;
|
bool connected = 2;
|
||||||
|
string error = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManagementState contains the latest state of a management connection
|
// ManagementState contains the latest state of a management connection
|
||||||
message ManagementState {
|
message ManagementState {
|
||||||
string URL = 1;
|
string URL = 1;
|
||||||
bool connected = 2;
|
bool connected = 2;
|
||||||
|
string error = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RelayState contains the latest state of the relay
|
||||||
|
message RelayState {
|
||||||
|
string URI = 1;
|
||||||
|
bool available = 2;
|
||||||
|
string error = 3;
|
||||||
|
}
|
||||||
|
|
||||||
// FullStatus contains the full state held by the Status instance
|
// FullStatus contains the full state held by the Status instance
|
||||||
message FullStatus {
|
message FullStatus {
|
||||||
ManagementState managementState = 1;
|
ManagementState managementState = 1;
|
||||||
SignalState signalState = 2;
|
SignalState signalState = 2;
|
||||||
LocalPeerState localPeerState = 3;
|
LocalPeerState localPeerState = 3;
|
||||||
repeated PeerState peers = 4;
|
repeated PeerState peers = 4;
|
||||||
|
repeated RelayState relays = 5;
|
||||||
}
|
}
|
@ -13,5 +13,5 @@ script_path=$(dirname $(realpath "$0"))
|
|||||||
cd "$script_path"
|
cd "$script_path"
|
||||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
|
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
|
||||||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
|
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
|
||||||
protoc -I ./ ./daemon.proto --go_out=../ --go-grpc_out=../
|
protoc -I ./ ./daemon.proto --go_out=../ --go-grpc_out=../ --experimental_allow_proto3_optional
|
||||||
cd "$old_pwd"
|
cd "$old_pwd"
|
@ -21,6 +21,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/version"
|
"github.com/netbirdio/netbird/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const probeThreshold = time.Second * 5
|
||||||
|
|
||||||
// Server for service control.
|
// Server for service control.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
rootCtx context.Context
|
rootCtx context.Context
|
||||||
@ -37,6 +39,12 @@ type Server struct {
|
|||||||
proto.UnimplementedDaemonServiceServer
|
proto.UnimplementedDaemonServiceServer
|
||||||
|
|
||||||
statusRecorder *peer.Status
|
statusRecorder *peer.Status
|
||||||
|
|
||||||
|
mgmProbe *internal.Probe
|
||||||
|
signalProbe *internal.Probe
|
||||||
|
relayProbe *internal.Probe
|
||||||
|
wgProbe *internal.Probe
|
||||||
|
lastProbe time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type oauthAuthFlow struct {
|
type oauthAuthFlow struct {
|
||||||
@ -53,7 +61,11 @@ func New(ctx context.Context, configPath, logFile string) *Server {
|
|||||||
latestConfigInput: internal.ConfigInput{
|
latestConfigInput: internal.ConfigInput{
|
||||||
ConfigPath: configPath,
|
ConfigPath: configPath,
|
||||||
},
|
},
|
||||||
logFile: logFile,
|
logFile: logFile,
|
||||||
|
mgmProbe: internal.NewProbe(),
|
||||||
|
signalProbe: internal.NewProbe(),
|
||||||
|
relayProbe: internal.NewProbe(),
|
||||||
|
wgProbe: internal.NewProbe(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +117,7 @@ func (s *Server) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if err := internal.RunClient(ctx, config, s.statusRecorder); err != nil {
|
if err := internal.RunClientWithProbes(ctx, config, s.statusRecorder, s.mgmProbe, s.signalProbe, s.relayProbe, s.wgProbe); err != nil {
|
||||||
log.Errorf("init connections: %v", err)
|
log.Errorf("init connections: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -409,7 +421,7 @@ func (s *Server) Up(callerCtx context.Context, _ *proto.UpRequest) (*proto.UpRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if err := internal.RunClient(ctx, s.config, s.statusRecorder); err != nil {
|
if err := internal.RunClientWithProbes(ctx, s.config, s.statusRecorder, s.mgmProbe, s.signalProbe, s.relayProbe, s.wgProbe); err != nil {
|
||||||
log.Errorf("run client connection: %v", err)
|
log.Errorf("run client connection: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -433,7 +445,7 @@ func (s *Server) Down(_ context.Context, _ *proto.DownRequest) (*proto.DownRespo
|
|||||||
return &proto.DownResponse{}, nil
|
return &proto.DownResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status starts engine work in the daemon.
|
// Status returns the daemon status
|
||||||
func (s *Server) Status(
|
func (s *Server) Status(
|
||||||
_ context.Context,
|
_ context.Context,
|
||||||
msg *proto.StatusRequest,
|
msg *proto.StatusRequest,
|
||||||
@ -455,6 +467,8 @@ func (s *Server) Status(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if msg.GetFullPeerStatus {
|
if msg.GetFullPeerStatus {
|
||||||
|
s.runProbes()
|
||||||
|
|
||||||
fullStatus := s.statusRecorder.GetFullStatus()
|
fullStatus := s.statusRecorder.GetFullStatus()
|
||||||
pbFullStatus := toProtoFullStatus(fullStatus)
|
pbFullStatus := toProtoFullStatus(fullStatus)
|
||||||
statusResponse.FullStatus = pbFullStatus
|
statusResponse.FullStatus = pbFullStatus
|
||||||
@ -463,6 +477,20 @@ func (s *Server) Status(
|
|||||||
return &statusResponse, nil
|
return &statusResponse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) runProbes() {
|
||||||
|
if time.Since(s.lastProbe) > probeThreshold {
|
||||||
|
managementHealthy := s.mgmProbe.Probe()
|
||||||
|
signalHealthy := s.signalProbe.Probe()
|
||||||
|
relayHealthy := s.relayProbe.Probe()
|
||||||
|
wgProbe := s.wgProbe.Probe()
|
||||||
|
|
||||||
|
// Update last time only if all probes were successful
|
||||||
|
if managementHealthy && signalHealthy && relayHealthy && wgProbe {
|
||||||
|
s.lastProbe = time.Now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetConfig of the daemon.
|
// GetConfig of the daemon.
|
||||||
func (s *Server) GetConfig(_ context.Context, _ *proto.GetConfigRequest) (*proto.GetConfigResponse, error) {
|
func (s *Server) GetConfig(_ context.Context, _ *proto.GetConfigRequest) (*proto.GetConfigResponse, error) {
|
||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
@ -503,13 +531,20 @@ func toProtoFullStatus(fullStatus peer.FullStatus) *proto.FullStatus {
|
|||||||
SignalState: &proto.SignalState{},
|
SignalState: &proto.SignalState{},
|
||||||
LocalPeerState: &proto.LocalPeerState{},
|
LocalPeerState: &proto.LocalPeerState{},
|
||||||
Peers: []*proto.PeerState{},
|
Peers: []*proto.PeerState{},
|
||||||
|
Relays: []*proto.RelayState{},
|
||||||
}
|
}
|
||||||
|
|
||||||
pbFullStatus.ManagementState.URL = fullStatus.ManagementState.URL
|
pbFullStatus.ManagementState.URL = fullStatus.ManagementState.URL
|
||||||
pbFullStatus.ManagementState.Connected = fullStatus.ManagementState.Connected
|
pbFullStatus.ManagementState.Connected = fullStatus.ManagementState.Connected
|
||||||
|
if err := fullStatus.ManagementState.Error; err != nil {
|
||||||
|
pbFullStatus.ManagementState.Error = err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
pbFullStatus.SignalState.URL = fullStatus.SignalState.URL
|
pbFullStatus.SignalState.URL = fullStatus.SignalState.URL
|
||||||
pbFullStatus.SignalState.Connected = fullStatus.SignalState.Connected
|
pbFullStatus.SignalState.Connected = fullStatus.SignalState.Connected
|
||||||
|
if err := fullStatus.SignalState.Error; err != nil {
|
||||||
|
pbFullStatus.SignalState.Error = err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
pbFullStatus.LocalPeerState.IP = fullStatus.LocalPeerState.IP
|
pbFullStatus.LocalPeerState.IP = fullStatus.LocalPeerState.IP
|
||||||
pbFullStatus.LocalPeerState.PubKey = fullStatus.LocalPeerState.PubKey
|
pbFullStatus.LocalPeerState.PubKey = fullStatus.LocalPeerState.PubKey
|
||||||
@ -518,17 +553,34 @@ func toProtoFullStatus(fullStatus peer.FullStatus) *proto.FullStatus {
|
|||||||
|
|
||||||
for _, peerState := range fullStatus.Peers {
|
for _, peerState := range fullStatus.Peers {
|
||||||
pbPeerState := &proto.PeerState{
|
pbPeerState := &proto.PeerState{
|
||||||
IP: peerState.IP,
|
IP: peerState.IP,
|
||||||
PubKey: peerState.PubKey,
|
PubKey: peerState.PubKey,
|
||||||
ConnStatus: peerState.ConnStatus.String(),
|
ConnStatus: peerState.ConnStatus.String(),
|
||||||
ConnStatusUpdate: timestamppb.New(peerState.ConnStatusUpdate),
|
ConnStatusUpdate: timestamppb.New(peerState.ConnStatusUpdate),
|
||||||
Relayed: peerState.Relayed,
|
Relayed: peerState.Relayed,
|
||||||
Direct: peerState.Direct,
|
Direct: peerState.Direct,
|
||||||
LocalIceCandidateType: peerState.LocalIceCandidateType,
|
LocalIceCandidateType: peerState.LocalIceCandidateType,
|
||||||
RemoteIceCandidateType: peerState.RemoteIceCandidateType,
|
RemoteIceCandidateType: peerState.RemoteIceCandidateType,
|
||||||
Fqdn: peerState.FQDN,
|
LocalIceCandidateEndpoint: peerState.LocalIceCandidateEndpoint,
|
||||||
|
RemoteIceCandidateEndpoint: peerState.RemoteIceCandidateEndpoint,
|
||||||
|
Fqdn: peerState.FQDN,
|
||||||
|
LastWireguardHandshake: timestamppb.New(peerState.LastWireguardHandshake),
|
||||||
|
BytesRx: peerState.BytesRx,
|
||||||
|
BytesTx: peerState.BytesTx,
|
||||||
}
|
}
|
||||||
pbFullStatus.Peers = append(pbFullStatus.Peers, pbPeerState)
|
pbFullStatus.Peers = append(pbFullStatus.Peers, pbPeerState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, relayState := range fullStatus.Relays {
|
||||||
|
pbRelayState := &proto.RelayState{
|
||||||
|
URI: relayState.URI.String(),
|
||||||
|
Available: relayState.Err == nil,
|
||||||
|
}
|
||||||
|
if err := relayState.Err; err != nil {
|
||||||
|
pbRelayState.Error = err.Error()
|
||||||
|
}
|
||||||
|
pbFullStatus.Relays = append(pbFullStatus.Relays, pbRelayState)
|
||||||
|
}
|
||||||
|
|
||||||
return &pbFullStatus
|
return &pbFullStatus
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,12 @@ type WGIface struct {
|
|||||||
filter PacketFilter
|
filter PacketFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WGStats struct {
|
||||||
|
LastHandshake time.Time
|
||||||
|
TxBytes int64
|
||||||
|
RxBytes int64
|
||||||
|
}
|
||||||
|
|
||||||
// IsUserspaceBind indicates whether this interfaces is userspace with bind.ICEBind
|
// IsUserspaceBind indicates whether this interfaces is userspace with bind.ICEBind
|
||||||
func (w *WGIface) IsUserspaceBind() bool {
|
func (w *WGIface) IsUserspaceBind() bool {
|
||||||
return w.userspaceBind
|
return w.userspaceBind
|
||||||
@ -139,3 +145,8 @@ func (w *WGIface) GetDevice() *DeviceWrapper {
|
|||||||
|
|
||||||
return w.tun.Wrapper()
|
return w.tun.Wrapper()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetStats returns the last handshake time, rx and tx bytes for the given peer
|
||||||
|
func (w *WGIface) GetStats(peerKey string) (WGStats, error) {
|
||||||
|
return w.configurer.getStats(peerKey)
|
||||||
|
}
|
||||||
|
@ -14,4 +14,5 @@ type wgConfigurer interface {
|
|||||||
addAllowedIP(peerKey string, allowedIP string) error
|
addAllowedIP(peerKey string, allowedIP string) error
|
||||||
removeAllowedIP(peerKey string, allowedIP string) error
|
removeAllowedIP(peerKey string, allowedIP string) error
|
||||||
close()
|
close()
|
||||||
|
getStats(peerKey string) (WGStats, error)
|
||||||
}
|
}
|
||||||
|
@ -207,3 +207,15 @@ func (c *wgKernelConfigurer) configure(config wgtypes.Config) error {
|
|||||||
|
|
||||||
func (c *wgKernelConfigurer) close() {
|
func (c *wgKernelConfigurer) close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *wgKernelConfigurer) getStats(peerKey string) (WGStats, error) {
|
||||||
|
peer, err := c.getPeer(c.deviceName, peerKey)
|
||||||
|
if err != nil {
|
||||||
|
return WGStats{}, fmt.Errorf("get wireguard stats: %w", err)
|
||||||
|
}
|
||||||
|
return WGStats{
|
||||||
|
LastHandshake: peer.LastHandshakeTime,
|
||||||
|
TxBytes: peer.TransmitBytes,
|
||||||
|
RxBytes: peer.ReceiveBytes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -207,6 +208,93 @@ func (t *wgUSPConfigurer) close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *wgUSPConfigurer) getStats(peerKey string) (WGStats, error) {
|
||||||
|
ipc, err := t.device.IpcGet()
|
||||||
|
if err != nil {
|
||||||
|
return WGStats{}, fmt.Errorf("ipc get: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stats, err := findPeerInfo(ipc, peerKey, []string{
|
||||||
|
"last_handshake_time_sec",
|
||||||
|
"last_handshake_time_nsec",
|
||||||
|
"tx_bytes",
|
||||||
|
"rx_bytes",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return WGStats{}, fmt.Errorf("find peer info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sec, err := strconv.ParseInt(stats["last_handshake_time_sec"], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return WGStats{}, fmt.Errorf("parse handshake sec: %w", err)
|
||||||
|
}
|
||||||
|
nsec, err := strconv.ParseInt(stats["last_handshake_time_nsec"], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return WGStats{}, fmt.Errorf("parse handshake nsec: %w", err)
|
||||||
|
}
|
||||||
|
txBytes, err := strconv.ParseInt(stats["tx_bytes"], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return WGStats{}, fmt.Errorf("parse tx_bytes: %w", err)
|
||||||
|
}
|
||||||
|
rxBytes, err := strconv.ParseInt(stats["rx_bytes"], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return WGStats{}, fmt.Errorf("parse rx_bytes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return WGStats{
|
||||||
|
LastHandshake: time.Unix(sec, nsec),
|
||||||
|
TxBytes: txBytes,
|
||||||
|
RxBytes: rxBytes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findPeerInfo(ipcInput string, peerKey string, searchConfigKeys []string) (map[string]string, error) {
|
||||||
|
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parse key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hexKey := hex.EncodeToString(peerKeyParsed[:])
|
||||||
|
|
||||||
|
lines := strings.Split(ipcInput, "\n")
|
||||||
|
|
||||||
|
configFound := map[string]string{}
|
||||||
|
foundPeer := false
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
// If we're within the details of the found peer and encounter another public key,
|
||||||
|
// this means we're starting another peer's details. So, stop.
|
||||||
|
if strings.HasPrefix(line, "public_key=") && foundPeer {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identify the peer with the specific public key
|
||||||
|
if line == fmt.Sprintf("public_key=%s", hexKey) {
|
||||||
|
foundPeer = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range searchConfigKeys {
|
||||||
|
if foundPeer && strings.HasPrefix(line, key+"=") {
|
||||||
|
v := strings.SplitN(line, "=", 2)
|
||||||
|
configFound[v[0]] = v[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: use multierr
|
||||||
|
for _, key := range searchConfigKeys {
|
||||||
|
if _, ok := configFound[key]; !ok {
|
||||||
|
return configFound, fmt.Errorf("config key not found: %s", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundPeer {
|
||||||
|
return nil, fmt.Errorf("peer not found: %s", peerKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
return configFound, nil
|
||||||
|
}
|
||||||
|
|
||||||
func toWgUserspaceString(wgCfg wgtypes.Config) string {
|
func toWgUserspaceString(wgCfg wgtypes.Config) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
if wgCfg.PrivateKey != nil {
|
if wgCfg.PrivateKey != nil {
|
||||||
|
104
iface/wg_configurer_usp_test.go
Normal file
104
iface/wg_configurer_usp_test.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package iface
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ipcFixture = `
|
||||||
|
private_key=e84b5a6d2717c1003a13b431570353dbaca9146cf150c5f8575680feba52027a
|
||||||
|
listen_port=12912
|
||||||
|
public_key=b85996fecc9c7f1fc6d2572a76eda11d59bcd20be8e543b15ce4bd85a8e75a33
|
||||||
|
preshared_key=188515093e952f5f22e865cef3012e72f8b5f0b598ac0309d5dacce3b70fcf52
|
||||||
|
allowed_ip=192.168.4.4/32
|
||||||
|
endpoint=[abcd:23::33%2]:51820
|
||||||
|
public_key=58402e695ba1772b1cc9309755f043251ea77fdcf10fbe63989ceb7e19321376
|
||||||
|
tx_bytes=38333
|
||||||
|
rx_bytes=2224
|
||||||
|
allowed_ip=192.168.4.6/32
|
||||||
|
persistent_keepalive_interval=111
|
||||||
|
endpoint=182.122.22.19:3233
|
||||||
|
public_key=662e14fd594556f522604703340351258903b64f35553763f19426ab2a515c58
|
||||||
|
endpoint=5.152.198.39:51820
|
||||||
|
allowed_ip=192.168.4.10/32
|
||||||
|
allowed_ip=192.168.4.11/32
|
||||||
|
tx_bytes=1212111
|
||||||
|
rx_bytes=1929999999
|
||||||
|
protocol_version=1
|
||||||
|
errno=0
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
func Test_findPeerInfo(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
peerKey string
|
||||||
|
searchKeys []string
|
||||||
|
want map[string]string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "single",
|
||||||
|
peerKey: "58402e695ba1772b1cc9309755f043251ea77fdcf10fbe63989ceb7e19321376",
|
||||||
|
searchKeys: []string{"tx_bytes"},
|
||||||
|
want: map[string]string{
|
||||||
|
"tx_bytes": "38333",
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple",
|
||||||
|
peerKey: "58402e695ba1772b1cc9309755f043251ea77fdcf10fbe63989ceb7e19321376",
|
||||||
|
searchKeys: []string{"tx_bytes", "rx_bytes"},
|
||||||
|
want: map[string]string{
|
||||||
|
"tx_bytes": "38333",
|
||||||
|
"rx_bytes": "2224",
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "lastpeer",
|
||||||
|
peerKey: "662e14fd594556f522604703340351258903b64f35553763f19426ab2a515c58",
|
||||||
|
searchKeys: []string{"tx_bytes", "rx_bytes"},
|
||||||
|
want: map[string]string{
|
||||||
|
"tx_bytes": "1212111",
|
||||||
|
"rx_bytes": "1929999999",
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "peer not found",
|
||||||
|
peerKey: "1111111111111111111111111111111111111111111111111111111111111111",
|
||||||
|
searchKeys: nil,
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "key not found",
|
||||||
|
peerKey: "662e14fd594556f522604703340351258903b64f35553763f19426ab2a515c58",
|
||||||
|
searchKeys: []string{"tx_bytes", "unknown_key"},
|
||||||
|
want: map[string]string{
|
||||||
|
"tx_bytes": "1212111",
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
res, err := hex.DecodeString(tt.peerKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
key, err := wgtypes.NewKey(res)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
got, err := findPeerInfo(ipcFixture, key.String(), tt.searchKeys)
|
||||||
|
assert.Equalf(t, tt.wantErr, err != nil, fmt.Sprintf("findPeerInfo(%v, %v, %v)", ipcFixture, key.String(), tt.searchKeys))
|
||||||
|
assert.Equalf(t, tt.want, got, "findPeerInfo(%v, %v, %v)", ipcFixture, key.String(), tt.searchKeys)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -17,4 +17,5 @@ type Client interface {
|
|||||||
GetDeviceAuthorizationFlow(serverKey wgtypes.Key) (*proto.DeviceAuthorizationFlow, error)
|
GetDeviceAuthorizationFlow(serverKey wgtypes.Key) (*proto.DeviceAuthorizationFlow, error)
|
||||||
GetPKCEAuthorizationFlow(serverKey wgtypes.Key) (*proto.PKCEAuthorizationFlow, error)
|
GetPKCEAuthorizationFlow(serverKey wgtypes.Key) (*proto.PKCEAuthorizationFlow, error)
|
||||||
GetNetworkMap() (*proto.NetworkMap, error)
|
GetNetworkMap() (*proto.NetworkMap, error)
|
||||||
|
IsHealthy() bool
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import (
|
|||||||
|
|
||||||
// ConnStateNotifier is a wrapper interface of the status recorders
|
// ConnStateNotifier is a wrapper interface of the status recorders
|
||||||
type ConnStateNotifier interface {
|
type ConnStateNotifier interface {
|
||||||
MarkManagementDisconnected()
|
MarkManagementDisconnected(error)
|
||||||
MarkManagementConnected()
|
MarkManagementConnected()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ func (c *GrpcClient) Sync(msgHandler func(msg *proto.SyncResponse) error) error
|
|||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
backOff.Reset() // reset backoff counter after successful connection
|
backOff.Reset() // reset backoff counter after successful connection
|
||||||
c.notifyDisconnected()
|
c.notifyDisconnected(err)
|
||||||
log.Warnf("disconnected from the Management service but will retry silently. Reason: %v", err)
|
log.Warnf("disconnected from the Management service but will retry silently. Reason: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -283,6 +283,32 @@ func (c *GrpcClient) GetServerPublicKey() (*wgtypes.Key, error) {
|
|||||||
return &serverKey, nil
|
return &serverKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsHealthy probes the gRPC connection and returns false on errors
|
||||||
|
func (c *GrpcClient) IsHealthy() bool {
|
||||||
|
switch c.conn.GetState() {
|
||||||
|
case connectivity.TransientFailure:
|
||||||
|
return false
|
||||||
|
case connectivity.Connecting:
|
||||||
|
return true
|
||||||
|
case connectivity.Shutdown:
|
||||||
|
return true
|
||||||
|
case connectivity.Idle:
|
||||||
|
case connectivity.Ready:
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(c.ctx, 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
_, err := c.realClient.GetServerKey(ctx, &proto.Empty{})
|
||||||
|
if err != nil {
|
||||||
|
c.notifyDisconnected(err)
|
||||||
|
log.Warnf("health check returned: %s", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
c.notifyConnected()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (c *GrpcClient) login(serverKey wgtypes.Key, req *proto.LoginRequest) (*proto.LoginResponse, error) {
|
func (c *GrpcClient) login(serverKey wgtypes.Key, req *proto.LoginRequest) (*proto.LoginResponse, error) {
|
||||||
if !c.ready() {
|
if !c.ready() {
|
||||||
return nil, fmt.Errorf("no connection to management")
|
return nil, fmt.Errorf("no connection to management")
|
||||||
@ -400,14 +426,14 @@ func (c *GrpcClient) GetPKCEAuthorizationFlow(serverKey wgtypes.Key) (*proto.PKC
|
|||||||
return flowInfoResp, nil
|
return flowInfoResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GrpcClient) notifyDisconnected() {
|
func (c *GrpcClient) notifyDisconnected(err error) {
|
||||||
c.connStateCallbackLock.RLock()
|
c.connStateCallbackLock.RLock()
|
||||||
defer c.connStateCallbackLock.RUnlock()
|
defer c.connStateCallbackLock.RUnlock()
|
||||||
|
|
||||||
if c.connStateCallback == nil {
|
if c.connStateCallback == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.connStateCallback.MarkManagementDisconnected()
|
c.connStateCallback.MarkManagementDisconnected(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GrpcClient) notifyConnected() {
|
func (c *GrpcClient) notifyConnected() {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/system"
|
"github.com/netbirdio/netbird/client/system"
|
||||||
"github.com/netbirdio/netbird/management/proto"
|
"github.com/netbirdio/netbird/management/proto"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type MockClient struct {
|
type MockClient struct {
|
||||||
@ -16,6 +17,10 @@ type MockClient struct {
|
|||||||
GetPKCEAuthorizationFlowFunc func(serverKey wgtypes.Key) (*proto.PKCEAuthorizationFlow, error)
|
GetPKCEAuthorizationFlowFunc func(serverKey wgtypes.Key) (*proto.PKCEAuthorizationFlow, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockClient) IsHealthy() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MockClient) Close() error {
|
func (m *MockClient) Close() error {
|
||||||
if m.CloseFunc == nil {
|
if m.CloseFunc == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -35,6 +35,7 @@ type Client interface {
|
|||||||
GetStatus() Status
|
GetStatus() Status
|
||||||
Receive(msgHandler func(msg *proto.Message) error) error
|
Receive(msgHandler func(msg *proto.Message) error) error
|
||||||
Ready() bool
|
Ready() bool
|
||||||
|
IsHealthy() bool
|
||||||
WaitStreamConnected()
|
WaitStreamConnected()
|
||||||
SendToStream(msg *proto.EncryptedMessage) error
|
SendToStream(msg *proto.EncryptedMessage) error
|
||||||
Send(msg *proto.Message) error
|
Send(msg *proto.Message) error
|
||||||
|
@ -28,7 +28,7 @@ const defaultSendTimeout = 5 * time.Second
|
|||||||
|
|
||||||
// ConnStateNotifier is a wrapper interface of the status recorder
|
// ConnStateNotifier is a wrapper interface of the status recorder
|
||||||
type ConnStateNotifier interface {
|
type ConnStateNotifier interface {
|
||||||
MarkSignalDisconnected()
|
MarkSignalDisconnected(error)
|
||||||
MarkSignalConnected()
|
MarkSignalConnected()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ func (c *GrpcClient) Receive(msgHandler func(msg *proto.Message) error) error {
|
|||||||
// we need this reset because after a successful connection and a consequent error, backoff lib doesn't
|
// 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
|
// reset times and next try will start with a long delay
|
||||||
backOff.Reset()
|
backOff.Reset()
|
||||||
c.notifyDisconnected()
|
c.notifyDisconnected(err)
|
||||||
log.Warnf("disconnected from the Signal service but will retry silently. Reason: %v", err)
|
log.Warnf("disconnected from the Signal service but will retry silently. Reason: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -238,6 +238,35 @@ func (c *GrpcClient) Ready() bool {
|
|||||||
return c.signalConn.GetState() == connectivity.Ready || c.signalConn.GetState() == connectivity.Idle
|
return c.signalConn.GetState() == connectivity.Ready || c.signalConn.GetState() == connectivity.Idle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsHealthy probes the gRPC connection and returns false on errors
|
||||||
|
func (c *GrpcClient) IsHealthy() bool {
|
||||||
|
switch c.signalConn.GetState() {
|
||||||
|
case connectivity.TransientFailure:
|
||||||
|
return false
|
||||||
|
case connectivity.Connecting:
|
||||||
|
return true
|
||||||
|
case connectivity.Shutdown:
|
||||||
|
return true
|
||||||
|
case connectivity.Idle:
|
||||||
|
case connectivity.Ready:
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(c.ctx, 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
_, err := c.realClient.Send(ctx, &proto.EncryptedMessage{
|
||||||
|
Key: c.key.PublicKey().String(),
|
||||||
|
RemoteKey: "dummy",
|
||||||
|
Body: nil,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.notifyDisconnected(err)
|
||||||
|
log.Warnf("health check returned: %s", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
c.notifyConnected()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// WaitStreamConnected waits until the client is connected to the Signal stream
|
// WaitStreamConnected waits until the client is connected to the Signal stream
|
||||||
func (c *GrpcClient) WaitStreamConnected() {
|
func (c *GrpcClient) WaitStreamConnected() {
|
||||||
|
|
||||||
@ -383,14 +412,14 @@ func (c *GrpcClient) receive(stream proto.SignalExchange_ConnectStreamClient,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GrpcClient) notifyDisconnected() {
|
func (c *GrpcClient) notifyDisconnected(err error) {
|
||||||
c.connStateCallbackLock.RLock()
|
c.connStateCallbackLock.RLock()
|
||||||
defer c.connStateCallbackLock.RUnlock()
|
defer c.connStateCallbackLock.RUnlock()
|
||||||
|
|
||||||
if c.connStateCallback == nil {
|
if c.connStateCallback == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.connStateCallback.MarkSignalDisconnected()
|
c.connStateCallback.MarkSignalDisconnected(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GrpcClient) notifyConnected() {
|
func (c *GrpcClient) notifyConnected() {
|
||||||
|
@ -15,6 +15,10 @@ type MockClient struct {
|
|||||||
SendFunc func(msg *proto.Message) error
|
SendFunc func(msg *proto.Message) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sm *MockClient) IsHealthy() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (sm *MockClient) Close() error {
|
func (sm *MockClient) Close() error {
|
||||||
if sm.CloseFunc == nil {
|
if sm.CloseFunc == nil {
|
||||||
return nil
|
return nil
|
||||||
|
Loading…
Reference in New Issue
Block a user