config: the LAN scanner joins house.go (V-410)
Pure move, with one comment corrected on the way. NetScanConfig.Rate said "0 ⇒ 50"; netscan.DefaultRate is 100 and has been since the package was written, and deploy/mavend.json sets 100 explicitly. The three sibling defaults now name the constant they come from rather than restating a number that can drift again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,6 @@ import (
|
|||||||
"github.com/kami/maven/internal/delivery/ntfysink"
|
"github.com/kami/maven/internal/delivery/ntfysink"
|
||||||
"github.com/kami/maven/internal/delivery/telegramsink"
|
"github.com/kami/maven/internal/delivery/telegramsink"
|
||||||
"github.com/kami/maven/internal/morning"
|
"github.com/kami/maven/internal/morning"
|
||||||
"github.com/kami/maven/internal/netscan"
|
|
||||||
"github.com/kami/maven/internal/update"
|
"github.com/kami/maven/internal/update"
|
||||||
"github.com/kami/maven/internal/vision"
|
"github.com/kami/maven/internal/vision"
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
@@ -285,51 +284,6 @@ type Config struct {
|
|||||||
NetScan *NetScanConfig `json:"netscan,omitempty"`
|
NetScan *NetScanConfig `json:"netscan,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetScanConfig — the LAN scanner block (Vikunja #257). Dark until
|
|
||||||
// `"enabled": true`.
|
|
||||||
//
|
|
||||||
// The important field is Subnets, and it is the ONLY source of a scan target.
|
|
||||||
// Nothing an utterance, a router or a scanned host says can widen or move the
|
|
||||||
// range: internal/netscan.Scanner.Scan takes no target argument at all. Each
|
|
||||||
// subnet must be private and no larger than netscan.MaxPrefixHosts addresses
|
|
||||||
// (a /22), enforced at config load rather than at the first spoken scan.
|
|
||||||
type NetScanConfig struct {
|
|
||||||
// Subnets — CIDRs to scan, "192.168.1.0/24".
|
|
||||||
Subnets []string `json:"subnets,omitempty"`
|
|
||||||
|
|
||||||
// Ports — TCP ports to try per host. Empty ⇒ 22, 80, 443, 8080.
|
|
||||||
Ports []int `json:"ports,omitempty"`
|
|
||||||
|
|
||||||
// Timeout — per-connection budget. 0 ⇒ 400ms.
|
|
||||||
Timeout Duration `json:"timeout,omitempty"`
|
|
||||||
|
|
||||||
// Rate — connections per second across the whole scan. 0 ⇒ 50. Low on
|
|
||||||
// purpose: a scan should look like background traffic, not a portscan.
|
|
||||||
Rate int `json:"rate,omitempty"`
|
|
||||||
|
|
||||||
// MaxHosts — cap on addresses probed per scan. 0 ⇒ 256.
|
|
||||||
MaxHosts int `json:"max_hosts,omitempty"`
|
|
||||||
|
|
||||||
// Enabled — false (the default) keeps a written block dark.
|
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetScanner maps the config block onto the netscan package's own type.
|
|
||||||
// ok=false when absent or disabled, so validation and daemon wiring cannot
|
|
||||||
// drift on the mapping.
|
|
||||||
func (c *Config) NetScanner() (netscan.Config, bool) {
|
|
||||||
if c.NetScan == nil || !c.NetScan.Enabled {
|
|
||||||
return netscan.Config{}, false
|
|
||||||
}
|
|
||||||
return netscan.Config{
|
|
||||||
Subnets: c.NetScan.Subnets,
|
|
||||||
Ports: c.NetScan.Ports,
|
|
||||||
Timeout: time.Duration(c.NetScan.Timeout),
|
|
||||||
Rate: c.NetScan.Rate,
|
|
||||||
MaxHosts: c.NetScan.MaxHosts,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// PraxisConfig — maven's connection to the Praxis attention service.
|
// PraxisConfig — maven's connection to the Praxis attention service.
|
||||||
type PraxisConfig struct {
|
type PraxisConfig struct {
|
||||||
// URL — the Praxis HTTP API base URL (e.g. "http://localhost:9742").
|
// URL — the Praxis HTTP API base URL (e.g. "http://localhost:9742").
|
||||||
@@ -1286,10 +1240,7 @@ func (c *Config) applyDefaults() {
|
|||||||
|
|
||||||
c.normaliseSmartHome()
|
c.normaliseSmartHome()
|
||||||
|
|
||||||
// Same rule for the scanner.
|
c.normaliseNetScan()
|
||||||
if c.NetScan != nil && !c.NetScan.Enabled {
|
|
||||||
c.NetScan = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Same rule for the crawler: a block that neither answers on demand nor
|
// Same rule for the crawler: a block that neither answers on demand nor
|
||||||
// watches anything has nothing to do, so it is normalised to "off".
|
// watches anything has nothing to do, so it is normalised to "off".
|
||||||
@@ -1445,12 +1396,8 @@ func (c *Config) validate() error {
|
|||||||
if err := c.validateSmartHome(); err != nil {
|
if err := c.validateSmartHome(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// A scanner pointed at the public internet, or at a /8, fails here rather
|
if err := c.validateNetScan(); err != nil {
|
||||||
// than after the packets have already left.
|
return err
|
||||||
if nc, ok := c.NetScanner(); ok {
|
|
||||||
if err := netscan.Validate(nc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// A media dir that cannot be created, or a vision endpoint that is a typo,
|
// A media dir that cannot be created, or a vision endpoint that is a typo,
|
||||||
// used to be logged at wiring time and the capability just stayed off. A
|
// used to be logged at wiring time and the capability just stayed off. A
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/kami/maven/internal/netscan"
|
||||||
"github.com/kami/maven/internal/smarthome"
|
"github.com/kami/maven/internal/smarthome"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -107,3 +108,69 @@ func (c *Config) validateSmartHome() error {
|
|||||||
}
|
}
|
||||||
return smarthome.Validate(hc)
|
return smarthome.Validate(hc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NetScanConfig — the LAN scanner block (Vikunja #257). Dark until
|
||||||
|
// `"enabled": true`.
|
||||||
|
//
|
||||||
|
// The important field is Subnets, and it is the ONLY source of a scan target.
|
||||||
|
// Nothing an utterance, a router or a scanned host says can widen or move the
|
||||||
|
// range: internal/netscan.Scanner.Scan takes no target argument at all. Each
|
||||||
|
// subnet must be private and no larger than netscan.MaxPrefixHosts addresses
|
||||||
|
// (a /22), enforced at config load rather than at the first spoken scan.
|
||||||
|
type NetScanConfig struct {
|
||||||
|
// Subnets — CIDRs to scan, "192.168.1.0/24".
|
||||||
|
Subnets []string `json:"subnets,omitempty"`
|
||||||
|
|
||||||
|
// Ports — TCP ports to try per host. Empty ⇒ netscan.DefaultPorts
|
||||||
|
// (22, 80, 443, 8080).
|
||||||
|
Ports []int `json:"ports,omitempty"`
|
||||||
|
|
||||||
|
// Timeout — per-connection budget. 0 ⇒ netscan.DefaultTimeout (400ms).
|
||||||
|
Timeout Duration `json:"timeout,omitempty"`
|
||||||
|
|
||||||
|
// Rate — connections per second across the whole scan. 0 ⇒
|
||||||
|
// netscan.DefaultRate (100). Low on purpose: a scan should look like
|
||||||
|
// background traffic, not a portscan.
|
||||||
|
Rate int `json:"rate,omitempty"`
|
||||||
|
|
||||||
|
// MaxHosts — cap on addresses probed per scan. 0 ⇒ netscan.DefaultMaxHosts
|
||||||
|
// (256).
|
||||||
|
MaxHosts int `json:"max_hosts,omitempty"`
|
||||||
|
|
||||||
|
// Enabled — false (the default) keeps a written block dark.
|
||||||
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetScanner maps the config block onto the netscan package's own type.
|
||||||
|
// ok=false when absent or disabled, so validation and daemon wiring cannot
|
||||||
|
// drift on the mapping.
|
||||||
|
func (c *Config) NetScanner() (netscan.Config, bool) {
|
||||||
|
if c.NetScan == nil || !c.NetScan.Enabled {
|
||||||
|
return netscan.Config{}, false
|
||||||
|
}
|
||||||
|
return netscan.Config{
|
||||||
|
Subnets: c.NetScan.Subnets,
|
||||||
|
Ports: c.NetScan.Ports,
|
||||||
|
Timeout: time.Duration(c.NetScan.Timeout),
|
||||||
|
Rate: c.NetScan.Rate,
|
||||||
|
MaxHosts: c.NetScan.MaxHosts,
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// normaliseNetScan applies the block's defaults. Same rule as the house: not
|
||||||
|
// enabled is the same as no block at all.
|
||||||
|
func (c *Config) normaliseNetScan() {
|
||||||
|
if c.NetScan != nil && !c.NetScan.Enabled {
|
||||||
|
c.NetScan = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateNetScan fails a scanner pointed at the public internet, or at a /8,
|
||||||
|
// here rather than after the packets have already left.
|
||||||
|
func (c *Config) validateNetScan() error {
|
||||||
|
nc, ok := c.NetScanner()
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return netscan.Validate(nc)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user