mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 08:16:39 +00:00
[client,management] Rewrite the SSH feature (#4015)
This commit is contained in:
@@ -81,6 +81,18 @@ type NsServerGroupStateOutput struct {
|
||||
Error string `json:"error" yaml:"error"`
|
||||
}
|
||||
|
||||
type SSHSessionOutput struct {
|
||||
Username string `json:"username" yaml:"username"`
|
||||
RemoteAddress string `json:"remoteAddress" yaml:"remoteAddress"`
|
||||
Command string `json:"command" yaml:"command"`
|
||||
JWTUsername string `json:"jwtUsername,omitempty" yaml:"jwtUsername,omitempty"`
|
||||
}
|
||||
|
||||
type SSHServerStateOutput struct {
|
||||
Enabled bool `json:"enabled" yaml:"enabled"`
|
||||
Sessions []SSHSessionOutput `json:"sessions" yaml:"sessions"`
|
||||
}
|
||||
|
||||
type OutputOverview struct {
|
||||
Peers PeersStateOutput `json:"peers" yaml:"peers"`
|
||||
CliVersion string `json:"cliVersion" yaml:"cliVersion"`
|
||||
@@ -100,6 +112,7 @@ type OutputOverview struct {
|
||||
Events []SystemEventOutput `json:"events" yaml:"events"`
|
||||
LazyConnectionEnabled bool `json:"lazyConnectionEnabled" yaml:"lazyConnectionEnabled"`
|
||||
ProfileName string `json:"profileName" yaml:"profileName"`
|
||||
SSHServerState SSHServerStateOutput `json:"sshServer" yaml:"sshServer"`
|
||||
}
|
||||
|
||||
func ConvertToStatusOutputOverview(resp *proto.StatusResponse, anon bool, statusFilter string, prefixNamesFilter []string, prefixNamesFilterMap map[string]struct{}, ipsFilter map[string]struct{}, connectionTypeFilter string, profName string) OutputOverview {
|
||||
@@ -121,6 +134,7 @@ func ConvertToStatusOutputOverview(resp *proto.StatusResponse, anon bool, status
|
||||
|
||||
relayOverview := mapRelays(pbFullStatus.GetRelays())
|
||||
peersOverview := mapPeers(resp.GetFullStatus().GetPeers(), statusFilter, prefixNamesFilter, prefixNamesFilterMap, ipsFilter, connectionTypeFilter)
|
||||
sshServerOverview := mapSSHServer(pbFullStatus.GetSshServerState())
|
||||
|
||||
overview := OutputOverview{
|
||||
Peers: peersOverview,
|
||||
@@ -141,6 +155,7 @@ func ConvertToStatusOutputOverview(resp *proto.StatusResponse, anon bool, status
|
||||
Events: mapEvents(pbFullStatus.GetEvents()),
|
||||
LazyConnectionEnabled: pbFullStatus.GetLazyConnectionEnabled(),
|
||||
ProfileName: profName,
|
||||
SSHServerState: sshServerOverview,
|
||||
}
|
||||
|
||||
if anon {
|
||||
@@ -190,6 +205,30 @@ func mapNSGroups(servers []*proto.NSGroupState) []NsServerGroupStateOutput {
|
||||
return mappedNSGroups
|
||||
}
|
||||
|
||||
func mapSSHServer(sshServerState *proto.SSHServerState) SSHServerStateOutput {
|
||||
if sshServerState == nil {
|
||||
return SSHServerStateOutput{
|
||||
Enabled: false,
|
||||
Sessions: []SSHSessionOutput{},
|
||||
}
|
||||
}
|
||||
|
||||
sessions := make([]SSHSessionOutput, 0, len(sshServerState.GetSessions()))
|
||||
for _, session := range sshServerState.GetSessions() {
|
||||
sessions = append(sessions, SSHSessionOutput{
|
||||
Username: session.GetUsername(),
|
||||
RemoteAddress: session.GetRemoteAddress(),
|
||||
Command: session.GetCommand(),
|
||||
JWTUsername: session.GetJwtUsername(),
|
||||
})
|
||||
}
|
||||
|
||||
return SSHServerStateOutput{
|
||||
Enabled: sshServerState.GetEnabled(),
|
||||
Sessions: sessions,
|
||||
}
|
||||
}
|
||||
|
||||
func mapPeers(
|
||||
peers []*proto.PeerState,
|
||||
statusFilter string,
|
||||
@@ -300,7 +339,7 @@ func ParseToYAML(overview OutputOverview) (string, error) {
|
||||
return string(yamlBytes), nil
|
||||
}
|
||||
|
||||
func ParseGeneralSummary(overview OutputOverview, showURL bool, showRelays bool, showNameServers bool) string {
|
||||
func ParseGeneralSummary(overview OutputOverview, showURL bool, showRelays bool, showNameServers bool, showSSHSessions bool) string {
|
||||
var managementConnString string
|
||||
if overview.ManagementState.Connected {
|
||||
managementConnString = "Connected"
|
||||
@@ -405,6 +444,41 @@ func ParseGeneralSummary(overview OutputOverview, showURL bool, showRelays bool,
|
||||
lazyConnectionEnabledStatus = "true"
|
||||
}
|
||||
|
||||
sshServerStatus := "Disabled"
|
||||
if overview.SSHServerState.Enabled {
|
||||
sessionCount := len(overview.SSHServerState.Sessions)
|
||||
if sessionCount > 0 {
|
||||
sessionWord := "session"
|
||||
if sessionCount > 1 {
|
||||
sessionWord = "sessions"
|
||||
}
|
||||
sshServerStatus = fmt.Sprintf("Enabled (%d active %s)", sessionCount, sessionWord)
|
||||
} else {
|
||||
sshServerStatus = "Enabled"
|
||||
}
|
||||
|
||||
if showSSHSessions && sessionCount > 0 {
|
||||
for _, session := range overview.SSHServerState.Sessions {
|
||||
var sessionDisplay string
|
||||
if session.JWTUsername != "" {
|
||||
sessionDisplay = fmt.Sprintf("[%s@%s -> %s] %s",
|
||||
session.JWTUsername,
|
||||
session.RemoteAddress,
|
||||
session.Username,
|
||||
session.Command,
|
||||
)
|
||||
} else {
|
||||
sessionDisplay = fmt.Sprintf("[%s@%s] %s",
|
||||
session.Username,
|
||||
session.RemoteAddress,
|
||||
session.Command,
|
||||
)
|
||||
}
|
||||
sshServerStatus += "\n " + sessionDisplay
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peersCountString := fmt.Sprintf("%d/%d Connected", overview.Peers.Connected, overview.Peers.Total)
|
||||
|
||||
goos := runtime.GOOS
|
||||
@@ -428,6 +502,7 @@ func ParseGeneralSummary(overview OutputOverview, showURL bool, showRelays bool,
|
||||
"Interface type: %s\n"+
|
||||
"Quantum resistance: %s\n"+
|
||||
"Lazy connection: %s\n"+
|
||||
"SSH Server: %s\n"+
|
||||
"Networks: %s\n"+
|
||||
"Forwarding rules: %d\n"+
|
||||
"Peers count: %s\n",
|
||||
@@ -444,6 +519,7 @@ func ParseGeneralSummary(overview OutputOverview, showURL bool, showRelays bool,
|
||||
interfaceTypeString,
|
||||
rosenpassEnabledStatus,
|
||||
lazyConnectionEnabledStatus,
|
||||
sshServerStatus,
|
||||
networks,
|
||||
overview.NumberOfForwardingRules,
|
||||
peersCountString,
|
||||
@@ -454,7 +530,7 @@ func ParseGeneralSummary(overview OutputOverview, showURL bool, showRelays bool,
|
||||
func ParseToFullDetailSummary(overview OutputOverview) string {
|
||||
parsedPeersString := parsePeers(overview.Peers, overview.RosenpassEnabled, overview.RosenpassPermissive)
|
||||
parsedEventsString := parseEvents(overview.Events)
|
||||
summary := ParseGeneralSummary(overview, true, true, true)
|
||||
summary := ParseGeneralSummary(overview, true, true, true, true)
|
||||
|
||||
return fmt.Sprintf(
|
||||
"Peers detail:"+
|
||||
@@ -746,4 +822,13 @@ func anonymizeOverview(a *anonymize.Anonymizer, overview *OutputOverview) {
|
||||
event.Metadata[k] = a.AnonymizeString(v)
|
||||
}
|
||||
}
|
||||
|
||||
for i, session := range overview.SSHServerState.Sessions {
|
||||
if host, port, err := net.SplitHostPort(session.RemoteAddress); err == nil {
|
||||
overview.SSHServerState.Sessions[i].RemoteAddress = fmt.Sprintf("%s:%s", a.AnonymizeIPString(host), port)
|
||||
} else {
|
||||
overview.SSHServerState.Sessions[i].RemoteAddress = a.AnonymizeIPString(session.RemoteAddress)
|
||||
}
|
||||
overview.SSHServerState.Sessions[i].Command = a.AnonymizeString(session.Command)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,6 +231,10 @@ var overview = OutputOverview{
|
||||
Networks: []string{
|
||||
"10.10.0.0/24",
|
||||
},
|
||||
SSHServerState: SSHServerStateOutput{
|
||||
Enabled: false,
|
||||
Sessions: []SSHSessionOutput{},
|
||||
},
|
||||
}
|
||||
|
||||
func TestConversionFromFullStatusToOutputOverview(t *testing.T) {
|
||||
@@ -385,7 +389,11 @@ func TestParsingToJSON(t *testing.T) {
|
||||
],
|
||||
"events": [],
|
||||
"lazyConnectionEnabled": false,
|
||||
"profileName":""
|
||||
"profileName":"",
|
||||
"sshServer":{
|
||||
"enabled":false,
|
||||
"sessions":[]
|
||||
}
|
||||
}`
|
||||
// @formatter:on
|
||||
|
||||
@@ -488,6 +496,9 @@ dnsServers:
|
||||
events: []
|
||||
lazyConnectionEnabled: false
|
||||
profileName: ""
|
||||
sshServer:
|
||||
enabled: false
|
||||
sessions: []
|
||||
`
|
||||
|
||||
assert.Equal(t, expectedYAML, yaml)
|
||||
@@ -554,6 +565,7 @@ NetBird IP: 192.168.178.100/16
|
||||
Interface type: Kernel
|
||||
Quantum resistance: false
|
||||
Lazy connection: false
|
||||
SSH Server: Disabled
|
||||
Networks: 10.10.0.0/24
|
||||
Forwarding rules: 0
|
||||
Peers count: 2/2 Connected
|
||||
@@ -563,7 +575,7 @@ Peers count: 2/2 Connected
|
||||
}
|
||||
|
||||
func TestParsingToShortVersion(t *testing.T) {
|
||||
shortVersion := ParseGeneralSummary(overview, false, false, false)
|
||||
shortVersion := ParseGeneralSummary(overview, false, false, false, false)
|
||||
|
||||
expectedString := fmt.Sprintf("OS: %s/%s", runtime.GOOS, runtime.GOARCH) + `
|
||||
Daemon version: 0.14.1
|
||||
@@ -578,6 +590,7 @@ NetBird IP: 192.168.178.100/16
|
||||
Interface type: Kernel
|
||||
Quantum resistance: false
|
||||
Lazy connection: false
|
||||
SSH Server: Disabled
|
||||
Networks: 10.10.0.0/24
|
||||
Forwarding rules: 0
|
||||
Peers count: 2/2 Connected
|
||||
|
||||
Reference in New Issue
Block a user