78 lines
2.2 KiB
Go
78 lines
2.2 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
// Wake is the magic-wake pattern sent to a host to rouse it: its MAC, the
|
|
// broadcast address to aim at, and how long to wait for the answer.
|
|
type Wake struct {
|
|
MAC string `toml:"mac"`
|
|
Broadcast string `toml:"broadcast"`
|
|
Wait Duration `toml:"wait"`
|
|
}
|
|
|
|
const (
|
|
DefaultWakeWait = 45 * time.Second
|
|
MinWakeWait = 5 * time.Second
|
|
)
|
|
|
|
// identityMode reports whether s is a recognized identity backend.
|
|
func identityMode(s string) bool {
|
|
return s == "off" || s == "tailscale" || s == "header"
|
|
}
|
|
|
|
// checkWake validates and defaults the magic-wake pattern of each host that has
|
|
// one.
|
|
func (c *Config) checkWake() *Error {
|
|
for name := range c.Hosts {
|
|
h := c.Hosts[name]
|
|
w := h.Wake
|
|
if w == nil {
|
|
continue
|
|
}
|
|
wakeField := fmt.Sprintf("hosts.%s.wake", name)
|
|
|
|
mac, err := net.ParseMAC(w.MAC)
|
|
if err != nil || len(mac) != 6 {
|
|
return &Error{Field: wakeField + ".mac", Msg: "must be a MAC address"}
|
|
}
|
|
|
|
if _, _, err := net.SplitHostPort(w.Broadcast); err != nil || w.Broadcast == "" {
|
|
return &Error{Field: wakeField + ".broadcast", Msg: "must be a non-empty host:port"}
|
|
}
|
|
|
|
if w.Wait.Duration == 0 {
|
|
w.Wait.Duration = DefaultWakeWait
|
|
} else if w.Wait.Duration < MinWakeWait {
|
|
return &Error{Field: wakeField + ".wait", Msg: "must be at least 5s"}
|
|
}
|
|
h.Wake = w
|
|
c.Hosts[name] = h
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// checkIdentity rejects an unrecognized identity backend.
|
|
func (c *Config) checkIdentity() *Error {
|
|
if !identityMode(c.Identity) {
|
|
return &Error{Field: "identity", Msg: `must be "off", "tailscale", or "header"`}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// checkPeers enforces the peers/identity contract for one route: peers may only
|
|
// be set with an identity backend on, and may not be an empty list.
|
|
func checkPeers(name string, peers []string, peersDefined, identityDefined bool, identity string) *Error {
|
|
peersField := fmt.Sprintf("routes.%s.peers", name)
|
|
switch {
|
|
case len(peers) > 0 && identityDefined && identity == "off":
|
|
return &Error{Field: peersField, Msg: "peers need identity = tailscale or header"}
|
|
case len(peers) == 0 && peersDefined && identityDefined && identity != "off":
|
|
return &Error{Field: peersField, Msg: "empty peers list"}
|
|
}
|
|
return nil
|
|
}
|