Documentation
¶
Overview ¶
Package agent は自宅側のエージェント(仕様 7 節)。 認証情報ファイルの鍵と最後の全体状態でトンネルとリスナーを先に立て、その後 stream に繋いで全体状態を受け取る。
Index ¶
- Constants
- Variables
- func ControlPath(path string) string
- func PinnedClient(pin [32]byte) *http.Client
- func PublicKey(path string) (wgtypes.Key, error)
- func Register(ctx context.Context, j *Join, name string) (permanentToken, address, confirmedName string, err error)
- func RotateKey(path string) (string, error)
- func Run(opts Options) error
- type DoctorAllowTargets
- type DoctorBudget
- type DoctorRefusal
- type DoctorResponse
- type DoctorRule
- type DoctorRuntimeState
- type DoctorStream
- type DoctorTunnel
- type DoctorWatchdog
- type Join
- type Options
Constants ¶
const ControlPathLimit = 103
ControlPathLimit は、どの OS でも収まる制御ソケットのパスの長さ(バイト)。sockaddr_un の sun_path は Linux と Windows で 108 バイト、macOS で 104 バイトで、終端の NUL を含む(仕様 11a 節)。
公開しているのは、繋げなかった理由が長さにあるかどうかを外から判定する読み手がいるためである (設計文書 10.2c 節の agent.control)。写しを持たせると、片方だけを直したときに判定が食い違う。
const DoctorCommand = "doctor"
DoctorCommand は制御ソケットに送る 1 行の要求である。
const ReasonHandshakePending = "handshake not established"
heartbeat は処理済み世代、トンネルの状態、ルールごとの状態をまとめる(仕様 5.2 節)。 ReasonHandshakePending は、トンネルはあるが WireGuard のハンドシェイクがまだ済んでいないときの理由。 適用直後の追送り(needsHandshakeFollowUp)がこの値で判定するので、文言を変えるときは両方に効く。
公開しているのは、制御ソケットの doctor の応答から同じ場合を見分ける読み手がいるためである (設計文書 10.2c 節)。応答が載せるのは理由の文字列だけで、ハンドシェイク待ちを tunnel.Status の Err による誤りと分ける材料は他に無い。写しを持たせると、この文言を変えたときに読み手だけが 取り残される。
Variables ¶
var ErrPinMismatch = errors.New("server certificate does not match the pinned hash")
ErrPinMismatch はサーバ証明書がピンと一致しない。teardown --purge のあとに立て直したサーバか、経路上の 第三者による TLS の終端で起きる。復帰は未使用の WGFT_JOIN による再登録(仕様 5.1 節)。
var ErrRegisterRejected = errors.New("registration rejected: join string already used or expired, or the name differs")
ErrRegisterRejected は登録が認証で拒否された(トークンが無効、名前違い)。
Functions ¶
func PinnedClient ¶
PinnedClient は証明書の SHA-256 がピンと一致するときだけ通す HTTP クライアント。 通常の検証(CA、ホスト名、期限)は使わない。IP 直打ちでも DNS 名でも同じ接続文字列が使える。
func Register ¶
func Register(ctx context.Context, j *Join, name string) (permanentToken, address, confirmedName string, err error)
Register は登録 API を呼び、恒久トークン、割り当てアドレス、確定した名前を返す。 name は任意(空なら送らない側に倣ってトークンに紐付いた名前で登録される)。
Types ¶
type DoctorAllowTargets ¶ added in v1.1.0
type DoctorAllowTargets struct {
// Set は一覧を持っているかどうか。偽なら、server はこのエージェントが届くどの宛先も指せる
Set bool `json:"set"`
// List は正規化した一覧。Set が偽なら空
List string `json:"list,omitempty"`
// Env は一覧を渡す設定の名前
Env string `json:"env"`
}
DoctorAllowTargets は宛先の許可一覧である。一覧の中身はエージェントのホストにしか無く、 server には届かない(設計文書 10.2c 節)。
type DoctorBudget ¶ added in v1.1.0
type DoctorBudget struct {
Proto proto.Proto `json:"proto"`
// Total は予算 T、InUse は今のフロー数 u である
Total int `json:"total"`
InUse int `json:"in_use"`
// RuleCap はルールが 2 本以上あるときのルール 1 本の上限 C、Reserve はルール 1 本あたりの
// 隔離予約 q、Rules は今受け付けているルールの数 N である
RuleCap int `json:"rule_cap"`
Reserve int `json:"reserve"`
Rules int `json:"rules"`
// Refusals は拒否の累計である。起点は DoctorRuntimeState.RefusalsSince
Refusals []DoctorRefusal `json:"refusals,omitempty"`
}
DoctorBudget は 1 つのプロトコルのフロー予算である。記号は設計文書 7a.10 節に合わせる。
type DoctorRefusal ¶ added in v1.1.0
type DoctorRefusal struct {
RuleID string `json:"rule_id"`
// Reason は budget、rule_cap、reserve のいずれか(設計文書 7a.10 節)
Reason resource.Reason `json:"reason"`
Count uint64 `json:"count"`
}
DoctorRefusal はルール 1 本の 1 つの理由の拒否の累計である。
type DoctorResponse ¶ added in v1.1.0
type DoctorResponse struct {
// Error は応答を組む処理が失敗したことと、その理由である。運用者に何が起きたかを伝えるために
// 載せる。値があるとき、残りの項目は無い
Error string `json:"error,omitempty"`
// AllowTargets は宛先の許可一覧である。起動時に決まって以後変わらず、実行時の排他も要らないので、
// 排他を取れなかった応答にも載る
AllowTargets *DoctorAllowTargets `json:"allow_targets,omitempty"`
// Stream は制御ストリームの観測である。streamMu だけで読めるので、実行時の排他を取れなかった
// 応答にも載る
Stream *DoctorStream `json:"stream,omitempty"`
// RuntimeState は実行時の排他の下でしか読めない状態である。排他を期限内に取れなければ無い
RuntimeState *DoctorRuntimeState `json:"runtime_state,omitempty"`
// RuntimeStateTimeout は、実行時の排他を取れなかったときに待った期限である。単位はナノ秒。
// 取れた場合は 0 になる
RuntimeStateTimeout time.Duration `json:"runtime_state_timeout,omitempty"`
}
DoctorResponse は doctor の応答である。1 行の JSON として送る。
Error があるときは、他の 3 つの項目が無い。応答を組む処理が panic したことを表すためである。 RuntimeState が無く RuntimeStateTimeout があるときは、実行時の状態を守る排他を期限内に 取れなかったことを表す。エージェントは生きているが内部の処理で詰まっている。
type DoctorRule ¶ added in v1.1.0
type DoctorRule struct {
ID string `json:"id"`
// State と Reason はハートビートが組み立てる proto.RuleStatus の値そのものである
State string `json:"state"`
Reason string `json:"reason,omitempty"`
// Proto は tcp か udp
Proto proto.Proto `json:"proto,omitempty"`
// Listeners はこのルールに属するリスナーの数、Listening はそのうち待ち受けを開けている数である
Listeners int `json:"listeners"`
Listening int `json:"listening"`
// BindErrors は待ち受けを開けなかったリスナーの数、BindError はその 1 つの理由である。
// 開けない原因はポートの衝突を指す
BindErrors int `json:"bind_errors"`
BindError string `json:"bind_error,omitempty"`
// TargetErrors は待ち受けは開いていて宛先に届かないリスナーの数、TargetError はその 1 つの
// 理由である。届かない原因は宛先の機器を指すので、運用者の次の行動が bind の失敗とは違う
TargetErrors int `json:"target_errors"`
TargetError string `json:"target_error,omitempty"`
// Sessions は中継が持っている接続の数である。TCP は公開側と宛先側の両方を数えるので、
// フロー予算の上限の対象とは一致しない。上限の対象の数は Flows である
Sessions int `json:"sessions"`
Flows int `json:"flows"`
}
DoctorRule はルール 1 本の状態である。リスナー 1 つずつは並べない。ポート範囲の幅に上限が無く、 listen_port=1-65535 のルール 1 本で 65535 個のリスナーができるので、そのまま並べると 1 行が 数 MB になる(設計文書 10.2c 節)。
type DoctorRuntimeState ¶ added in v1.1.0
type DoctorRuntimeState struct {
// Generation は最後に受け取って処理した全体状態の世代
Generation uint64 `json:"generation"`
Tunnel DoctorTunnel `json:"tunnel"`
// Rules はルールごとの状態である。リスナー 1 つずつは並べない。中継が無ければ項目ごと出ない
Rules []DoctorRule `json:"rules,omitempty"`
// Budgets はプロトコルごとのフロー予算である。中継が無ければ項目ごと出ない
Budgets []DoctorBudget `json:"budgets,omitempty"`
// RefusalsSince は Budgets の拒否の累計の起点、つまり今のトンネルを立てた時刻である。
// フロー予算はトンネルを立て直すたびに中継ごと作り直され、累計はそのたびに 0 に戻る
// (設計文書 10.2c 節)。中継が無ければゼロ値の時刻になる。項目そのものは必ず出るので、
// 読み手は IsZero で判定する
RefusalsSince time.Time `json:"refusals_since"`
}
DoctorRuntimeState は実行時の排他の下で 1 度に読んだ状態である。トンネル、ルール、フロー予算の 値はどれも同じ時点のものである。
type DoctorStream ¶ added in v1.1.0
type DoctorStream struct {
Connected bool `json:"connected"`
// DisconnectedAt と RetryAt、LastPingAt、LastPongAt は、値が無ければゼロ値の時刻になる。
// encoding/json の omitempty は struct に効かないので、項目そのものは必ず出る。読み手は
// IsZero で判定する
DisconnectedAt time.Time `json:"disconnected_at"`
DisconnectReason string `json:"disconnect_reason,omitempty"`
// Backoff は直近に待った再接続の間隔。単位はナノ秒
Backoff time.Duration `json:"backoff,omitempty"`
RetryAt time.Time `json:"retry_at"`
LastPingAt time.Time `json:"last_ping_at"`
LastPongAt time.Time `json:"last_pong_at"`
AwaitingPong bool `json:"awaiting_pong"`
}
DoctorStream は制御ストリームの観測の写しである。項目の意味は streamObservation にある。
type DoctorTunnel ¶ added in v1.1.0
type DoctorTunnel struct {
// Present はトンネルがあるかどうか。偽なら Reason がその理由を言う
Present bool `json:"present"`
// State は ok か error
State string `json:"state"`
Reason string `json:"reason,omitempty"`
// Endpoint は解決済みのエンドポイント。初回の名前解決に失敗したトンネルは持たない
Endpoint string `json:"endpoint,omitempty"`
// LastHandshake は今の device から読んだ最終ハンドシェイクである。watchdog が別に持つ値は
// トンネルを閉じても消えず、立て直した直後は前のトンネルの値が残るので、そちらは載せない。
// 成立していなければゼロ値の時刻になる。項目そのものは必ず出るので、読み手は IsZero で判定する
LastHandshake time.Time `json:"last_handshake"`
RxBytes int64 `json:"rx_bytes"`
TxBytes int64 `json:"tx_bytes"`
// StartedAt は今のトンネルを立てた時刻。トンネルが無ければゼロ値の時刻になる
StartedAt time.Time `json:"started_at"`
Watchdog DoctorWatchdog `json:"watchdog"`
}
DoctorTunnel はトンネルの状態である。State と Reason はハートビートが組み立てる値そのもので、 doctor のための 2 つ目の判定は持たない(設計文書 10.2c 節)。
type DoctorWatchdog ¶ added in v1.1.0
type DoctorWatchdog struct {
// RebuildInterval は判定に使う作り直しの間隔の実効値である。単位はナノ秒
RebuildInterval time.Duration `json:"rebuild_interval"`
// RetryAt は、作成に失敗して試し直しを待っている場合の予定の時刻。待っていなければゼロ値の
// 時刻になる。項目そのものは必ず出るので、読み手は IsZero で判定する
RetryAt time.Time `json:"retry_at"`
}
DoctorWatchdog はトンネルを作り直す判定の状態である。次の作り直しまでの残り時間は載せない。 残りは保持されておらず、示すには起点を求める規則を診断の側に写すことになるためである (設計文書 10.2c 節)。
type Join ¶
type Join struct {
Endpoint string // host:port(エージェント用 API)
Token string // 1 回限りの登録トークン
Pin [32]byte
// contains filtered or unexported fields
}
Join は接続文字列 wgft://host:port/token#sha256:<hex> の中身(仕様 5.1 節)。
type Options ¶
type Options struct {
// AllowTargets は接続してよい宛先の許可一覧(仕様 7 節、WGFT_AGENT_ALLOW_TARGETS)。
// nil なら制限せず、vpsd が配るどの宛先へも接続する
AllowTargets *allowtargets.List
CredentialsPath string // 認証情報ファイル
Join string // 接続文字列(WGFT_JOIN か --join)。初回登録に使う
Limits resource.Limits // 同時フロー数のプロセス全体の予算(仕様 7 節)。ゼロ値は既定値
Name string // エージェント名(WGFT_NAME か --name)。任意。接続文字列の発行時の名前に紐付いているので、与えなければトークンに紐付いた名前で登録される
Version string // 起動ログに出す wgft の版(cmd 側の effectiveVersion())。空なら "dev" として出す
}
Options は agent の起動オプション。
Directories
¶
| Path | Synopsis |
|---|---|
|
Package allowtargets は、エージェントが接続してよい宛先の一覧(設計文書 7 節)。
|
Package allowtargets は、エージェントが接続してよい宛先の一覧(設計文書 7 節)。 |
|
Package credentials はエージェントの認証情報ファイル(agent.json)を扱う(仕様 9 節)。
|
Package credentials はエージェントの認証情報ファイル(agent.json)を扱う(仕様 9 節)。 |