Initial commit
This commit is contained in:
commit
06036c89d9
29 changed files with 4891 additions and 0 deletions
137
checker/rules.go
Normal file
137
checker/rules.go
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2020-2026 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// This program is offered under a commercial and under the AGPL license.
|
||||
// For commercial licensing, contact us at <contact@happydomain.org>.
|
||||
//
|
||||
// For AGPL licensing:
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
sdk "git.happydns.org/checker-sdk-go/checker"
|
||||
)
|
||||
|
||||
// Each concern is its own rule so results surface independently in the UI
|
||||
// rather than being squashed under a single aggregated verdict.
|
||||
func Rules() []sdk.CheckRule {
|
||||
return []sdk.CheckRule{
|
||||
&reachabilityRule{},
|
||||
&handshakeRule{},
|
||||
&protocolVersionRule{},
|
||||
&bannerSoftwareRule{},
|
||||
&knownVulnsRule{},
|
||||
newKexAlgorithmsRule(),
|
||||
newHostKeyAlgorithmsRule(),
|
||||
newCipherAlgorithmsRule(),
|
||||
newMacAlgorithmsRule(),
|
||||
&strictKexRule{},
|
||||
&preauthCompressionRule{},
|
||||
&hostKeyStrengthRule{},
|
||||
&sshfpAlignmentRule{},
|
||||
&sshfpHashRule{},
|
||||
&authMethodsRule{},
|
||||
}
|
||||
}
|
||||
|
||||
// On failure, returns a single error state the caller should emit to short-circuit its rule.
|
||||
func loadSSHData(ctx context.Context, obs sdk.ObservationGetter) (*SSHData, *sdk.CheckState) {
|
||||
var data SSHData
|
||||
if err := obs.Get(ctx, ObservationKeySSH, &data); err != nil {
|
||||
return nil, &sdk.CheckState{
|
||||
Status: sdk.StatusError,
|
||||
Message: fmt.Sprintf("failed to load SSH observation: %v", err),
|
||||
Code: "ssh.observation_error",
|
||||
}
|
||||
}
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
// reachableEndpoints returns the subset of endpoints that completed
|
||||
// enough of the handshake to expose algorithm data.
|
||||
func reachableEndpoints(eps []SSHProbe) []SSHProbe {
|
||||
var out []SSHProbe
|
||||
for _, ep := range eps {
|
||||
if len(ep.KEX) > 0 {
|
||||
out = append(out, ep)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// severityToStatus maps an Issue severity to the SDK Status enum.
|
||||
func severityToStatus(sev string) sdk.Status {
|
||||
switch sev {
|
||||
case SeverityCrit:
|
||||
return sdk.StatusCrit
|
||||
case SeverityWarn:
|
||||
return sdk.StatusWarn
|
||||
case SeverityInfo:
|
||||
return sdk.StatusInfo
|
||||
default:
|
||||
return sdk.StatusOK
|
||||
}
|
||||
}
|
||||
|
||||
func issueToState(is Issue) sdk.CheckState {
|
||||
st := sdk.CheckState{
|
||||
Status: severityToStatus(is.Severity),
|
||||
Message: is.Message,
|
||||
Code: is.Code,
|
||||
Subject: is.Endpoint,
|
||||
}
|
||||
if is.Fix != "" {
|
||||
st.Meta = map[string]any{"fix": is.Fix}
|
||||
}
|
||||
return st
|
||||
}
|
||||
|
||||
func statesFromIssues(issues []Issue) []sdk.CheckState {
|
||||
out := make([]sdk.CheckState, 0, len(issues))
|
||||
for _, is := range issues {
|
||||
out = append(out, issueToState(is))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func passState(code, message string) sdk.CheckState {
|
||||
return sdk.CheckState{
|
||||
Status: sdk.StatusOK,
|
||||
Message: message,
|
||||
Code: code,
|
||||
}
|
||||
}
|
||||
|
||||
func notTestedState(code, message string) sdk.CheckState {
|
||||
return sdk.CheckState{
|
||||
Status: sdk.StatusUnknown,
|
||||
Message: message,
|
||||
Code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// noEndpointsState is returned by rules that need probe output but got
|
||||
// nothing (no endpoints collected at all).
|
||||
func noEndpointsState(code string) sdk.CheckState {
|
||||
return sdk.CheckState{
|
||||
Status: sdk.StatusUnknown,
|
||||
Message: "No SSH endpoints were probed.",
|
||||
Code: code,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue