Documentation
¶
Overview ¶
Package wg は VPS の wg0(このファイル)と、カーネルモードのエージェントの単一ピアの インタフェース(agent.go、設計文書 7b 節)の WireGuard インタフェースを宣言に収束させる (仕様 4, 9 節、設計文書 7a.7 節)。インタフェースの作成とアドレス・MTU は netlink で、鍵・ポート・ ピアは wgctrl で扱う。作成、MTU、アドレスの収束は両者で共有する。停止時には何も削除しない。internal/vpsd と internal/agent を import しない(internal/platform/linux の bind 中ポート検査だけを使う)。
Index ¶
- func AgentKeyHolders(iface string, current, previous wgtypes.Key) ([]string, error)
- func AgentPrivilegeRefusal(err error) error
- func AgentRouteInterface(dst netip.Addr) (string, error)
- func AgentStagingName(iface string) string
- func AgentWireGuardSupport() error
- func DeleteLink(iface string) (bool, error)
- func Ensure(cfg Config) (changes []string, err error)
- func EnsureAgent(cfg AgentConfig) (changes []string, err error)
- func KernelDeviceNames() ([]string, error)
- func OtherDeviceWithKey(iface string, key wgtypes.Key) (string, bool)
- func Owned(iface string, expectedKey wgtypes.Key) (owned, exists bool, err error)
- func Status(iface string) (*wgtypes.Device, error)
- type AgentConfig
- type AgentState
- type Config
- type DeviceState
- type NotOursError
- type OverlapError
- type Ownership
- type Peer
- type PeerState
- type ServerPeer
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AgentKeyHolders ¶ added in v1.2.0
AgentKeyHolders lists the WireGuard devices other than iface that hold current or previous (design.md 7b.4 節). A link left under an old name after WGFT_WG_INTERFACE changed is one; the agent warns about it at startup and never deletes it. The zero key matches nothing.
func AgentPrivilegeRefusal ¶ added in v1.2.0
AgentPrivilegeRefusal turns a permission failure of a read the agent makes before converging, such as AgentOwnership, into the same prerequisite refusal EnsureAgent returns. Other errors are returned as they are.
func AgentRouteInterface ¶ added in v1.2.0
AgentRouteInterface returns the name of the interface the kernel's routing, policy rules included, sends traffic to dst through (design.md 7b.1 節). The agent compares it with its own interface after converging: an address or route overlap check reads only the main table, so a rule that sends the server's tunnel address to another table, such as Tailscale's table 52, is seen only here.
func AgentStagingName ¶ added in v1.2.0
AgentStagingName is the name the agent's link has while it is being created (design.md 7b.4 節). It is derived from the interface name, so every start that creates the same interface uses the same staging name and can clear what a crash left under it. It is 15 bytes, the kernel's limit.
func AgentWireGuardSupport ¶ added in v1.2.0
func AgentWireGuardSupport() error
AgentWireGuardSupport asks the kernel for the wireguard generic netlink family, without writing anything and without CAP_NET_ADMIN (design.md 7b.5 節). The lookup makes the kernel try to load the module first, as creating the link does, so a family still missing after it is the same prerequisite refusal createLink makes for a kernel without WireGuard. Any other failure is returned as it is; it says nothing about the module.
func DeleteLink ¶
DeleteLink は iface を削除する。無ければ false, nil(撤去を途中からでも走らせられるように)。 所有判定は呼び出し側(Owned)で済ませてから呼ぶこと。
func Ensure ¶
Ensure は wg0 を宣言に収束させ、変えた点を返す。なければ作り、あれば差分だけ直す。 手作業で変えられたアドレス、MTU、ポート、ピア、秘密鍵はここで宣言に戻る。 ただし収束するのは「自分が作ったインタフェース」だけで、既存の同名インタフェースは 鍵が一致する(=過去に自分が作った)ときにしか触らない。一致しなければ何も書かずに conflictError を返す(仕様 9 節)。
func EnsureAgent ¶ added in v1.2.0
func EnsureAgent(cfg AgentConfig) (changes []string, err error)
EnsureAgent converges the agent's kernel WireGuard interface to cfg and returns what it changed (design.md 7b.1, 7b.4 節). A missing link is created. An existing link is converged only when it is ours by the current or the previous key; the judgement is made before the first write, and a link that is not ours is left as it is and reported as *NotOursError with a dry run. A link that held the previous key ends up with the current one. Before the first write it also refuses, with a plain error, when the agent's address range overlaps an address or a route on another interface (design.md 7b.1 節).
Converged: MTU, the IPv4 address (exactly cfg.Address), the private key, the peer set (only the server; any other peer is removed), the server's AllowedIPs (exactly its /32), its endpoint when cfg.Server.Endpoint is valid, its keepalive, and the up flag. The listen port is not converged: the agent dials out and has no fixed port, and setting one would rebind the socket.
A link created by this call is deleted again if a later step fails. A permission failure is a prerequisite refusal, and so is a kernel without WireGuard.
func KernelDeviceNames ¶ added in v1.2.0
KernelDeviceNames lists every kernel WireGuard device on the host, whatever its key. Agent teardown shows them when it has no credentials to judge ownership with, and deletes none of them.
func OtherDeviceWithKey ¶
OtherDeviceWithKey は、iface 以外に同じ秘密鍵を持つ WireGuard デバイス(=改名で残った自分の 旧インタフェース)があればその名前を返す。列挙できなければ黙って false。
Types ¶
type AgentConfig ¶ added in v1.2.0
type AgentConfig struct {
// Interface is the link name, wgft0 unless WGFT_WG_INTERFACE says otherwise.
Interface string
// PrivateKey is the key in the agent's credentials file. It must not be zero: a link created
// with the zero key could never be judged ours again.
PrivateKey wgtypes.Key
// PreviousKey is the key before the last rotate-key, kept in the credentials file so that a
// link still holding it after a crash in the middle of rotate-key, or after rotate-key ran
// while the agent was stopped, is still ours (design.md 7b.4 節). Zero when there is none;
// the zero key never makes a link ours.
PreviousKey wgtypes.Key
// Address is the agent's own tunnel address with the band, as the full state's wg.address
// gives it (10.200.0.2/24).
Address netip.Prefix
MTU int
Server ServerPeer
}
AgentConfig declares the agent's kernel WireGuard interface (design.md 7b.1 節).
type AgentState ¶ added in v1.2.0
type AgentState struct {
Exists bool
// Kind is the link type ("wireguard" for a WireGuard device).
Kind string
Ownership Ownership
// The rest is read only for a WireGuard device.
PublicKey wgtypes.Key // the public half of the key the device holds; zero if it holds none
ListenPort int // the port the kernel chose; shown only
MTU int
Addresses []netip.Prefix // IPv4 only, as EnsureAgent converges them
Up bool
Peers []PeerState
}
AgentState is what InspectAgent reads back of the agent's interface: what agent doctor's dataplane.interface shows and what the agent compares with the last convergence. It carries the public key only, never the private key.
func InspectAgent ¶ added in v1.2.0
func InspectAgent(iface string, current, previous wgtypes.Key) (AgentState, error)
InspectAgent reads iface without changing anything and judges its ownership against current and previous. Reading a WireGuard device needs CAP_NET_ADMIN; without it the error wraps os.ErrPermission, which agent doctor reports as needs_cap_net_admin.
type Config ¶
type Config struct {
Interface string
PrivateKey wgtypes.Key
ListenPort int
Address netip.Prefix // 10.200.0.1/24
MTU int
Peers []Peer
// AdoptExisting が真のときだけ、鍵の一致しない既存インタフェースを引き継ぐ。
// 既定は偽で、他人のインタフェースは収束させず、何も書かずに中止する。
AdoptExisting bool
// KeepPeers が真のとき、ピアには触れず(Peers は読まない)、インタフェース、鍵、ポート、
// アドレス、MTU だけを収束させる。起動時のインタフェースの立ち上げに使い、ピアの変更は
// 公開の前後に分けて行うトランザクションに任せる(設計文書 7a.3 節)。
KeepPeers bool
}
Config は wg0 の宣言。
type DeviceState ¶ added in v0.5.0
type DeviceState struct {
Exists bool
// Kind is the link type ("wireguard" for a WireGuard device).
Kind string
// The rest is read only for a WireGuard device.
PrivateKey wgtypes.Key
ListenPort int
Addresses []netip.Prefix // IPv4 only, as Ensure converges them
Up bool
Peers []Peer // a peer whose AllowedIPs is not exactly one /32 has an invalid Address
}
DeviceState is what Inspect reads back of iface: enough to tell whether it still is what the last transaction converged it to (design.md 7a.3 節: 実際の状態への収束).
func Inspect ¶ added in v0.5.0
func Inspect(iface string) (DeviceState, error)
Inspect reads iface without changing anything: whether it exists, its link type and, for a WireGuard device, its key, listen port, IPv4 addresses, up flag and peers. It is a few netlink reads, cheap enough for every Observe.
type NotOursError ¶ added in v1.2.0
type NotOursError struct {
Interface string
Ownership Ownership // ForeignKey or NotWireGuard
Kind string // the link type
// Keyless is set for a WireGuard link that holds no private key at all.
Keyless bool
// DryRun lists what EnsureAgent would have changed had the link been the agent's. Empty for
// teardown and for a link that is not WireGuard.
DryRun []string
}
NotOursError is returned when a link with the agent's interface name exists but is not the agent's. It is a plain error, exit code 1 (design.md 7b.4, 11b 節): nothing was written, and once the operator removes or renames that link the next start goes through.
func (*NotOursError) Error ¶ added in v1.2.0
func (e *NotOursError) Error() string
type OverlapError ¶ added in v1.2.0
type OverlapError struct {
Range netip.Prefix
What string // the overlapping address or route and its interface
Server netip.Addr
Interface string
// CoversServer is true when the overlap also takes traffic to the server's tunnel address away
// from the agent's interface.
CoversServer bool
}
OverlapError is EnsureAgent's refusal of an address range that overlaps an address or a route on another interface (design.md 7b.1 節). It is a plain error, exit code 1. The agent tells it apart because the first convergence of the process ends the process on it, and a later one retries.
func (*OverlapError) Error ¶ added in v1.2.0
func (e *OverlapError) Error() string
type Ownership ¶ added in v1.2.0
type Ownership int
Ownership is what a link with the agent's interface name is to the agent (design.md 7b.4 節).
const ( // Absent: there is no link with the name. Absent Ownership = iota // OwnedByCurrentKey: a WireGuard link holding the key in the credentials file. OwnedByCurrentKey // OwnedByPreviousKey: a WireGuard link holding the key before the last rotate-key. The next // EnsureAgent moves it to the current key. OwnedByPreviousKey // ForeignKey: a WireGuard link whose key is neither, including the zero key. Never touched. ForeignKey // NotWireGuard: a link of another type with the name. Never touched. NotWireGuard )
func AgentOwnership ¶ added in v1.2.0
AgentOwnership reads what the link named iface is to an agent holding current and previous (design.md 7b.4 節). It changes nothing. The mode gate and teardown judge the agent's leftovers with it.
func DeleteAgentLink ¶ added in v1.2.0
DeleteAgentLink deletes iface only when it is the agent's by the current or the previous key (design.md 10.3 節). A missing link is not an error: it returns Absent and false, so teardown can run again after a partial run. A link that is not ours is left as it is and reported as *NotOursError, whose text shows the `ip link del` recovery.
type PeerState ¶ added in v1.2.0
type PeerState struct {
PublicKey wgtypes.Key
AllowedIPs []netip.Prefix
Endpoint netip.AddrPort // zero when the peer has none
Keepalive time.Duration
// LastHandshake is a value to show, zero when there has been none. Judging whether it is
// recent enough belongs to server doctor's tunnel.handshake (design.md 10.2c 節).
LastHandshake time.Time
ReceiveBytes int64
TransmitBytes int64
}
PeerState is one peer of the agent's interface as the kernel reports it.
type ServerPeer ¶ added in v1.2.0
type ServerPeer struct {
PublicKey wgtypes.Key
// Address is vpsd's tunnel address. The peer's AllowedIPs is exactly its /32.
Address netip.Addr
// Endpoint is the server's address, already resolved: the caller resolves the endpoint's name
// and decides when to resolve it again (design.md 4, 7b.1 節). The zero value means "not
// resolved now": the endpoint the kernel has is kept, and a peer added now has none until a
// later call supplies one. A valid value is converged to, so passing the result of each new
// resolution moves the peer to it.
Endpoint netip.AddrPort
// Keepalive is the persistent keepalive, in whole seconds as the kernel keeps it. Zero turns
// it off.
Keepalive time.Duration
}
ServerPeer is the link's one peer, the server.