fix: harden config loading and ssh addresses, stop resolver on API errors
- read netssh.yaml from the user config directory only, not from the working directory - refuse addresses from NetBox or the cache that are neither an IP address nor a hostname (ssh read "-oProxyCommand=…" as an option) - resolver chain stops at an API failure; only "no address" falls through to the next strategy - netssh --help and -h show netssh's help - start at most one background cache refresh per 5 minutes - validate the legacy netbox.url - page through all IP addresses of a host - CI: run format check, vet, and tests on pull requests and main - changelog for v0.0.25 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
1 parent
6e80b733dc
commit
4287b7b650
19 files changed
+317
-30
No files matched your search
@@ -2,6 +2,7 @@ package ssh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -142,6 +143,18 @@ type Result struct {
|
||||
Notice string
|
||||
}
|
||||
|
||||
var destinationName = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]*$`)
|
||||
|
||||
// ValidAddress reports whether addr is an IP address or a hostname. Addresses
|
||||
// come from NetBox and the cache file; one such as "-oProxyCommand=…" would be
|
||||
// read by ssh as an option and run a command.
|
||||
func ValidAddress(addr string) bool {
|
||||
if _, err := netip.ParseAddr(addr); err == nil {
|
||||
return !strings.ContainsAny(addr, " \t\r\n")
|
||||
}
|
||||
return destinationName.MatchString(addr)
|
||||
}
|
||||
|
||||
var plainHostname = regexp.MustCompile(`^[A-Za-z0-9]([A-Za-z0-9._-]*[A-Za-z0-9])?$`)
|
||||
|
||||
// Apply replaces the destination at destIdx and inserts the configured -o
|
||||
|
||||
@@ -128,3 +128,17 @@ func TestQuote(t *testing.T) {
|
||||
t.Fatalf("got %s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidAddress(t *testing.T) {
|
||||
for _, addr := range []string{"10.0.0.1", "fd00:30::60", "fe80::1%eth0", "web01", "web01.example.com", "db_1.lan"} {
|
||||
if !ValidAddress(addr) {
|
||||
t.Errorf("ValidAddress(%q) = false, want true", addr)
|
||||
}
|
||||
}
|
||||
// ssh would read the first as an option and run the command.
|
||||
for _, addr := range []string{"-oProxyCommand=touch /tmp/pwned", "-J", "", "a b", "host;id", "user@host", "host/path", "fe80::1%eth0 x", "$(id)"} {
|
||||
if ValidAddress(addr) {
|
||||
t.Errorf("ValidAddress(%q) = true, want false", addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user