Documentation
¶
Index ¶
- func InterfaceCreate(cfg models.InterfaceConfig) error
- func InterfaceDelete(cfg models.InterfaceConfig) error
- func InterfaceUpdate(prev *models.InterfaceConfig, cfg models.InterfaceConfig) error
- func IsInterfaceExist(cfg models.InterfaceConfig) bool
- func SetBackend(b Backend)
- func WatchStorage(ctx context.Context, dir string) error
- type Backend
- type BackendInfo
- type Handler
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func InterfaceCreate ¶
func InterfaceCreate(cfg models.InterfaceConfig) error
func InterfaceDelete ¶
func InterfaceDelete(cfg models.InterfaceConfig) error
InterfaceDelete tears cfg's interface down and removes the OS-level link itself (netlink.LinkDel) — without the LinkDel call, DELETE /interfaces/{name} only dropped the agent's JSON record while the actual `ip link` survived on the host. Idempotent: a link that's already gone (e.g. removed by hand) is treated as already deleted rather than an error.
PreDown/PostDown hooks run around the teardown but, unlike InterfaceCreate's PreUp/PostUp (which abort on failure), are best-effort: removing the link is the whole point here, so a failing hook is logged and teardown continues.
func InterfaceUpdate ¶
func InterfaceUpdate(prev *models.InterfaceConfig, cfg models.InterfaceConfig) error
InterfaceUpdate reconfigures an already-existing link in place and reconciles its hooks: any rules the previous config set up (prev's PreDown/PostDown) are torn down first, then the new config's PreUp/PostUp set up the current ones. This lets an admin edit an interface — e.g. add or remove a tunnel's routing rules — and have them applied and reverted without recreating the link (which would drop its peers/clients). prev is nil on agent-startup re-apply, in which case only the new up-hooks run. The teardown side is best-effort so a rule that's already gone doesn't block the update.
func IsInterfaceExist ¶
func IsInterfaceExist(cfg models.InterfaceConfig) bool
func SetBackend ¶
func SetBackend(b Backend)
SetBackend selects the link backend for this process. Call it once, early in main, before loading interfaces. Not safe to call concurrently with interface operations.
func WatchStorage ¶
WatchStorage watches dir (the agent's config storage root, see agent/storage/fs.Dir) for interface config files disappearing while the agent is already running, and tears the corresponding link down immediately via InterfaceDelete — instead of leaving it dangling until the agent happens to restart (see Handler.DetectOrphans, which only catches this at startup).
Unlike DetectOrphans, this needs no "is this really mine" judgment call: dir is a directory this agent exclusively writes (*iface*.json) into via Set/Delete (agent/storage/fs.go) — there is no other source for files in it, so any file disappearing from it by definition was one of this agent's own interface records, however it disappeared (DELETE /interfaces/{name}, which already calls InterfaceDelete itself before removing the file — so this is a harmless idempotent no-op for that case, see InterfaceDelete's own existence check — or someone removing the file by hand while the agent is up, which is the actual gap this closes). A plain function rather than a Handler method: tearing down a link only needs netlink (InterfaceDelete), not storage.Storage or a wgctrl.Client, so there's no reason to make the caller open one just for this.
Runs until ctx is cancelled; logs (rather than returns) errors from individual events so a single bad event doesn't tear down the watch.
Types ¶
type Backend ¶
type Backend interface {
// Add brings the interface's OS link into existence. amnezia selects the
// interface type: true creates an AmneziaWG link (obfuscation-capable),
// false a plain WireGuard one — driven by the admin's "Amnezia Interface"
// toggle (see models.InterfaceConfig.IsAmnezia). Kernel: netlink RTM_NEWLINK
// with the matching kind. Userspace: the amneziawg-go device serves both, so
// the TUN is created the same way regardless.
Add(iface string, amnezia bool) error
// Delete removes the OS link. Kernel: netlink RTM_DELLINK. Userspace: close
// the amneziawg-go device (which removes the TUN). Idempotent: a link that's
// already gone is not an error.
Delete(iface string) error
// Exists reports whether the interface's OS link is present.
Exists(iface string) bool
// Up brings the link administratively up.
Up(iface string) error
// Down brings the link administratively down.
Down(iface string) error
// SetMTU sets the link MTU.
SetMTU(iface string, mtu int) error
// AddrAdd assigns addr (a CIDR like 10.0.0.1/24) to the link.
AddrAdd(iface, addr string) error
// SyncAddr makes addr the link's only address, removing any others first.
SyncAddr(iface, addr string) error
// Info reports what this backend can create on the current host — its kind,
// the interface variants it can bring up, and (kernel only) whether the
// AmneziaWG kernel module is present. Probed on each call (it shells out to
// modinfo for the kernel backend), so the agent calls it once at startup and
// caches the result (see agent.Run → models.HostInfo).
Info() BackendInfo
}
Backend abstracts the OS-level lifecycle of a WireGuard/AmneziaWG interface — the one part of the agent that differs between the two builds:
- kernel (agent/internal/kernel): the AmneziaWG kernel module, driven over netlink (vishvananda/netlink). Wired in by cmd/awg-agent.
- userspace (agent/internal/userspace): an in-process amneziawg-go TUN, with address/up/mtu done via the `ip` command (no netlink dependency, the way jwg / awg-quick's userspace path do it). Wired in by cmd/awg-agent-userspace.
Keeping this an interface (rather than either build importing the other) is what lets the userspace agent avoid pulling in vishvananda/netlink at all. Everything else the agent does is backend-agnostic:
- pushing the device config and reading peer stats via wgctrl, which speaks both the kernel genl family and the userspace UAPI socket;
- running PreUp/PostUp/PreDown/PostDown hooks (plain `sh -c`);
- storing interface configs (agent/storage).
type BackendInfo ¶
type BackendInfo struct {
// Kind identifies the backend: "kernel" or "userspace".
Kind string
// KernelModule reports whether the AmneziaWG kernel module is available on
// this host. Always false for the userspace backend (it needs no module).
KernelModule bool
// InterfaceKinds lists the interface variants creatable here: "amneziawg"
// and/or "wireguard".
InterfaceKinds []string
}
BackendInfo describes what the active link backend can create on the current host. Gathered once at startup (Backend.Info) and folded into the agent's GET /info response (models.HostInfo). Host-level facts that don't depend on the backend — whether Docker is usable, whether the agent runs in a container — are discovered separately by the agent package, not here.
func ActiveBackendInfo ¶
func ActiveBackendInfo() BackendInfo
ActiveBackendInfo returns the active backend's capabilities (see BackendInfo). SetBackend must have been called first.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
func (*Handler) DetectOrphans ¶
DetectOrphans returns the name of every live WireGuard interface on the host that h's storage has no record of — e.g. a DELETE /interfaces/{name} call's JSON write succeeded but its netlink teardown didn't (shouldn't happen anymore, see InterfaceDelete, but old data or a manual `ip link` could still produce this), or the agent's storage was wiped/replaced without the corresponding interfaces being torn down first.
Deliberately read-only: the agent can't tell "this is my own orphan" from "an administrator created an unrelated WireGuard interface by hand, with nothing to do with awg-admin" — deciding what to do about a mismatch is left to a human (see awg-admin's agent↔DB reconciliation), this just surfaces the list.
func (*Handler) One ¶
func (h *Handler) One(prev *models.InterfaceConfig, cfg models.InterfaceConfig) error
One applies cfg to the host: creates or (in place) updates the link, then pushes the full device config. prev is the previously-stored config for this interface (nil for a brand-new one), used by InterfaceUpdate to reconcile hooks on an in-place edit.
func (*Handler) StopEnabled ¶
func (h *Handler) StopEnabled()
StopEnabled tears down the OS link of every enabled interface (best effort), leaving the stored configs intact. It's called on agent shutdown so tunnels don't keep carrying traffic — and lifecycle PreDown/PostDown rules stay in effect — while the agent is gone. Disabled interfaces are skipped (their link is already down). On the next start, All → One re-creates the enabled ones.