Documentation
¶
Index ¶
- Variables
- func AdminClient(socket string) (api.AdminServiceClient, error)
- func AdminConn(socket string) (*grpc.ClientConn, error)
- func InstallSignalPolicy()
- func NewAutoAcceptingHostKeyCallback(stdout io.Writer, knownHostsFilename string) (ssh.HostKeyCallback, error)
- func NewHostKey() (ssh.Signer, error)
- func NewPromptingHostKeyCallback(stdin io.Reader, stdout io.Writer, knownHostsFilename string, proxied bool) (ssh.HostKeyCallback, error)
- func ProviderList() string
- func Signers(privateKeys []string, identitiesOnly bool) ([]ssh.Signer, func(), error)
- func SignersFromFiles(privateKeys []string) ([]ssh.Signer, error)
- func SignersFromFilesWith(privateKeys []string, passphrase func(string) ([]byte, error), ...) ([]ssh.Signer, error)
- func SignersWith(opts SignerOptions) ([]ssh.Signer, func(), error)
- type AgentRefusedError
- type AgentUnavailableError
- type AuthorizedKey
- type CredentialMode
- type Fetcher
- type GuestIdentity
- type GuestIdentityOptions
- type Host
- type KnownHosts
- type ReconnectTiming
- type RelayWarning
- type RelayWarningKind
- type SignerOptions
- type TunnelEvent
- type UserRef
Constants ¶
This section is empty.
Variables ¶
var ( // ErrUnknownHostKey is what KnownHosts.Check reports for a key that no // line of the file names. ErrUnknownHostKey = errors.New("host key is not known") // ErrHostKeyChanged is what KnownHosts.Check reports for a host whose line // names a different key. ErrHostKeyChanged = errors.New("host key has changed") )
var ClaimTimeout = 10 * time.Second
ClaimTimeout bounds how long Run waits for the session registry when it takes a name, for a Host whose own ClaimTimeout is zero.
Claim waits on two lock files, either of which can be held by a process that is stopped rather than slow — a wait no amount of patience resolves. The caller's context is not a bound in practice: the CLI runs Run on context.Background(), so without this a stuck registry hangs `upterm host` at startup forever while every read path already gives up after sessionQueryTimeout. Ten seconds matches those read paths, since they wait on the same locks.
A var, not a const, so that an embedder on a slower filesystem can set it as startup configuration.
Deprecated: set Host.ClaimTimeout. As a default it is startup configuration: set it before running any host.
var ErrNoInitialClient = internal.ErrNoInitialClient
ErrNoInitialClient is what a host told to await its initial client returns when nobody attached in time. Nothing ran, so it is recorded as startup_abandoned rather than a failure.
var ErrSessionAbandoned = errors.New("session abandoned before the command started")
ErrSessionAbandoned marks a session given up before its command started, as opposed to one that failed to start. A SessionCreatedCallback error that wraps it is recorded as startup_abandoned rather than startup_failed.
Declining the interactive confirmation is the case it exists for: the operator was shown the session and said no, nothing went wrong, and a record saying otherwise sends whoever reads it looking for a fault that never happened.
Functions ¶
func AdminClient ¶
func AdminClient(socket string) (api.AdminServiceClient, error)
func AdminConn ¶ added in v0.39.0
func AdminConn(socket string) (*grpc.ClientConn, error)
AdminConn is AdminClient's connection, for a caller that has to close it: a process that asks more than once in its life, such as an attached terminal's ~?, would otherwise keep a connection open per question.
func InstallSignalPolicy ¶ added in v0.30.0
func InstallSignalPolicy()
InstallSignalPolicy sets the process-wide signal dispositions a host needs: SIGPIPE converted to EPIPE, and SIGTTIN and SIGTTOU ignored. Starting a host installs it before it touches its terminal; an embedder that writes to the same stdout or reads the same stdin before then may call it earlier, and calling it twice is free.
SIGPIPE is fatal for writes to fd 1 and 2 and only for those; Go turns it into EPIPE everywhere else. So `upterm host … | head` would kill the whole session the instant head exits, taking the hosted command with it — the one failure mode headless operation must not have. Calling Notify converts it to EPIPE, and the error then travels the ordinary path: the stdout sink fails and is dropped.
SIGTTIN and SIGTTOU get SIG_IGN, not a handler. A backgrounded process reading its controlling terminal is sent SIGTTIN, and the default disposition stops it — so `upterm host … &` would suspend. With a handler installed the read returns EINTR and Go retries, which spins. Ignored, it returns EIO, which the host's stdin actor survives. SIGTTOU is the same story for writes, and it is why the ignores are installed here rather than beside the signal actor, where they used to be: Run assembles that only after the reverse tunnel is up, the version warning is printed and SessionCreatedCallback has written the banner, and from a terminal with `stty tostop` set the first of those writes stopped the host before the ignore existed. The prompting host-key callback's read of stdin was sent SIGTTIN the same way.
Ignoring SIGTTOU also means a background tcsetattr would succeed, which is why command.Run checks foreground ownership before touching terminal modes at all.
It belongs to this package rather than to the CLI, which is where the SIGPIPE conversion used to live and still is: an application that embeds Host.Run with Stdout set to its own os.Stdout never runs upterm's main, so it inherited the fatal disposition and died on its reader's close — before the sink could report the broken pipe and before the final session record was published.
Process-wide and permanent is the point. Scoping any of it to a session would leave the startup banner unprotected at one end and the shutdown drain unprotected at the other, and nothing here may ever call signal.Stop or signal.Reset: that would strip the policy from every other session in the same process. An embedder that calls Host.Run in-process inherits all three for the rest of the process's life, and so does everything else in that process — a library of its own that reads a background terminal would find the read returning EIO instead of the caller being stopped.
func NewAutoAcceptingHostKeyCallback ¶ added in v0.19.0
func NewAutoAcceptingHostKeyCallback(stdout io.Writer, knownHostsFilename string) (ssh.HostKeyCallback, error)
NewAutoAcceptingHostKeyCallback creates a host key callback that automatically accepts unknown host keys and adds them to the known_hosts file without prompting. This is similar to SSH's StrictHostKeyChecking=accept-new behavior: - Unknown host keys are automatically accepted and added to known_hosts - Known host keys are still validated (preventing MITM attacks on subsequent connections)
It takes no proxied flag: its message names the hostname and the key type, never the peer address.
func NewHostKey ¶ added in v0.30.0
NewHostKey generates the key the embedded sshd presents on both its doors and the key the relay is told to expect from this host. It is a session's key, not the operator's: fresh per run, never read from disk, never offered to the relay as an identity.
func NewPromptingHostKeyCallback ¶
func NewPromptingHostKeyCallback(stdin io.Reader, stdout io.Writer, knownHostsFilename string, proxied bool) (ssh.HostKeyCallback, error)
NewPromptingHostKeyCallback creates a host key callback that asks before accepting an unknown host key.
Set proxied when the transport passes through an HTTP proxy. x/crypto hands the callback the socket's peer, which is then the proxy rather than the server, and presenting it as the server's address is misleading — OpenSSH prints a placeholder in the same situation. It is display-only: knownhosts matches on the hostname argument and KnownHosts.Record stores only that, so verification is unaffected either way.
func ProviderList ¶ added in v0.27.0
func ProviderList() string
ProviderList names every supported provider and marks the ones that need an explicit host. It is the single source for both parse errors and the --authorized-user flag's help text, so the two cannot drift apart.
func Signers ¶
Signers returns the identities upterm host offers to the server, and a cleanup that releases the agent connection they may sign through.
With identitiesOnly, privateKeys is the whole set and must be non-empty: each entry must resolve to a signer, a public key file selects the agent key it names, and the agent is otherwise used only to sign a key it already holds that the file itself cannot supply — encrypted, or otherwise unparseable with a `.pub` sibling. Without it, the agent's keys are preferred when it has any, then the files that load, then a generated key.
Passphrases are prompted for on this process's terminal; a process that has none calls SignersWith instead.
func SignersFromFilesWith ¶ added in v0.30.0
func SignersFromFilesWith(privateKeys []string, passphrase func(string) ([]byte, error), onSkip func(string, error)) ([]ssh.Signer, error)
SignersFromFilesWith reads every key it can and skips the rest. A key that cannot be read never fails the set: the default key list is every file in ~/.ssh that exists, and one unreadable file must not stop a session.
func SignersWith ¶ added in v0.30.0
func SignersWith(opts SignerOptions) ([]ssh.Signer, func(), error)
SignersWith is Signers with the passphrase prompt and the skip report injected. The prompt reaches both paths — identitySigners takes one too — so a daemon, which has no terminal to prompt on, resolves an encrypted key the same way whether or not the identity list is the whole set.
Types ¶
type AgentRefusedError ¶ added in v0.35.0
AgentRefusedError is a redial whose SSH agent was reached but didn't sign: it couldn't list its keys, no longer holds the key, refused or failed the signature, or its connection closed underneath, the attempt's deadline among the causes. Key is the identity's SHA256 fingerprint.
func (*AgentRefusedError) Error ¶ added in v0.35.0
func (e *AgentRefusedError) Error() string
func (*AgentRefusedError) Unwrap ¶ added in v0.35.0
func (e *AgentRefusedError) Unwrap() error
type AgentUnavailableError ¶ added in v0.35.0
type AgentUnavailableError struct {
}
AgentUnavailableError is a redial that couldn't reach the SSH agent to sign: no socket, a connection refused, or no SSH_AUTH_SOCK when the session started. Socket is the one recorded then.
func (*AgentUnavailableError) Error ¶ added in v0.35.0
func (e *AgentUnavailableError) Error() string
func (*AgentUnavailableError) Unwrap ¶ added in v0.35.0
func (e *AgentUnavailableError) Unwrap() error
type AuthorizedKey ¶ added in v0.13.0
func AuthorizedKeysFromFile ¶ added in v0.13.0
func AuthorizedKeysFromFile(file string) (*AuthorizedKey, error)
func AuthorizedKeysFromUserRefs ¶ added in v0.27.0
func AuthorizedKeysFromUserRefs(ctx context.Context, refs []UserRef, proxyURL *url.URL, logger *slog.Logger) ([]*AuthorizedKey, error)
AuthorizedKeysFromUserRefs resolves refs using a default Fetcher. A non-nil proxyURL sends every fetch through that HTTP proxy.
type CredentialMode ¶ added in v0.27.0
type CredentialMode int
CredentialMode describes how a reference selects an authentication token.
const ( // CredentialNone never sends a credential. Every provider but GitHub. CredentialNone CredentialMode = iota // CredentialDefault defers to go-gh's own host and token resolution, // preserving GH_HOST and the enterprise environment variables. Used when a // GitHub reference names no explicit host. CredentialDefault // CredentialHostScoped uses only credentials stored for the named host. // GH_ENTERPRISE_TOKEN and GITHUB_ENTERPRISE_TOKEN are not host-scoped, so // honoring them here would send one instance's token to another. CredentialHostScoped )
type Fetcher ¶ added in v0.27.0
type Fetcher struct {
Logger *slog.Logger
// Transport, when set, is the base round tripper for every request. Tests
// use it to trust httptest certificates; production leaves it nil.
Transport http.RoundTripper
// contains filtered or unexported fields
}
Fetcher resolves user references to authorized keys.
func (*Fetcher) AuthorizedKeys ¶ added in v0.27.0
AuthorizedKeys fetches every reference, reporting all failures together. Any failure fails the whole call: continuing with a partial set can, in the limit, degrade "only alice may join" into "anyone may join".
type GuestIdentity ¶ added in v0.38.0
type GuestIdentity struct {
// contains filtered or unexported fields
}
GuestIdentity is the keys a guest offers, prepared once before the first attempt and offered again on every rejoin. Its Signers and Source are join.Identity's.
func NewGuestIdentity ¶ added in v0.38.0
func NewGuestIdentity(ctx context.Context, o GuestIdentityOptions) (*GuestIdentity, error)
NewGuestIdentity prepares the keys a guest offers. It runs before the first attempt, in cooked mode, under ctx: Ctrl-C there is SIGINT, and ends it with ctx's error. It works in ssh's order, so that a key the agent holds never asks for a passphrase:
- each file's public half, read without a passphrase: the file itself when it is a public key, which selects the agent key it names; a .pub beside it; the file's own key when it is unencrypted; or the public half an encrypted openssh-format file carries;
- the agent's keys, listed over a connection of their own that is closed at AgentTimeout or when ctx ends, so that a silent agent never spends the first join's budget. An agent that fails is skipped for the run, and a socket nobody listens on is no agent, as it is for OpenSSH;
- each file: the agent's key when the agent holds it, which needs no passphrase and lets a FIDO key sign, and otherwise the file's own key, decrypted with Passphrase if it must be.
Without IdentitiesOnly, every agent key comes first, then each file whose key the agent doesn't hold, and a file that doesn't load is skipped. With it, the entries are offered in order and no other agent key is, and an entry that doesn't load is a *join.IdentityError with Load set. A key named twice is offered once either way.
A key is generated only without IdentitiesOnly, when there is no agent key (no socket, one nobody listens on, or an agent that holds none) and no file. An agent that failed, with no file that loaded, is a *join.IdentityError with List set; files that all failed to load, with no agent key, are one with Load set.
func (*GuestIdentity) Signers ¶ added in v0.38.0
Signers is join.Identity.Signers: what one attempt offers, in order, and the release that closes the attempt's connection to the agent. A key the agent holds is offered by its public half, and reaches the agent only to sign, over a connection dialled under ctx that the attempt's other agent keys share. A key file's signer, and a generated key, are the ones prepared before the first attempt. Signers itself never fails: an agent that stopped answering, or no longer holds a key, fails that key's signature instead.
func (*GuestIdentity) Source ¶ added in v0.38.0
func (g *GuestIdentity) Source() join.KeySource
Source is join.Identity.Source: the identities as Signers offers them.
type GuestIdentityOptions ¶ added in v0.38.0
type GuestIdentityOptions struct {
// IdentitiesOnly says -i was given: Files is the whole set, each entry
// must resolve, and no other agent key is offered. An empty Files with
// IdentitiesOnly is an error, as `upterm host -i` makes it ("private-key
// was supplied but names no files"); it never falls back to the defaults.
IdentitiesOnly bool
Files []string // with IdentitiesOnly: -i's entries; otherwise the default files that exist
AgentSocket string // SSH_AUTH_SOCK
AgentTimeout time.Duration // bound on listing the agent's keys; 0 = 5 s
// Passphrase asks for an encrypted key file's passphrase, and returns
// promptly once ctx ends. It is asked only for a file whose key the agent
// doesn't hold. Nil leaves such a file unloaded.
Passphrase func(ctx context.Context, file string) ([]byte, error)
// OnSkip is told about each key file that didn't load, when another key
// did: "skipping <file>: <error>". OnAgentSkip is told why the agent
// failed or ran out of time listing its keys, when a key file loaded
// instead: "skipping the SSH agent: <error>". A socket nobody listens on
// is no agent, not one that failed, and isn't told. Both are called
// before NewGuestIdentity returns; nil is silent.
OnSkip func(file string, err error)
OnAgentSkip func(err error)
}
GuestIdentityOptions configures NewGuestIdentity.
type Host ¶
type Host struct {
Host string
// KeepAliveDuration paces the guest sshd's keepalive to each guest. The
// tunnel's own liveness is Reconnect's.
KeepAliveDuration time.Duration
Command []string
ForceCommand []string
Signers []ssh.Signer
// IdentitiesOnly says Signers is the whole identity set, as --private-key
// makes it: a redial never offers the session key ahead of it.
IdentitiesOnly bool
// Reconnect paces the tunnel's liveness and its redials. A field left zero
// takes its default.
Reconnect ReconnectTiming
// HostKey is the key the embedded sshd presents on both its doors and
// the key the relay is told to expect from this host. A session's key,
// not the operator's: Signers authenticate the tunnel and are used for
// nothing else. Left nil, Run generates one for that run and does not
// keep it, so a Host run twice presents two keys; a caller that needs
// the public half before Run — the CLI, to pin its own attach — sets it
// and it is used as given.
HostKey ssh.Signer
HostKeyCallback ssh.HostKeyCallback
AuthorizedKeys []*AuthorizedKey
AdminSocketFile string
SessionCreatedCallback func(context.Context, *api.GetSessionResponse) error
ClientJoinedCallback func(*api.Client)
ClientLeftCallback func(*api.Client)
Logger *slog.Logger
ReadOnly bool
AllowLocalTCPForwarding bool
// TunnelCallback is told when the tunnel to the relay is lost, and when
// it is back. It is called on a goroutine of the host's own, one event at
// a time and in the order they happened, so a callback that takes a while
// delays only the events behind it, not the redial. Of the events that
// happen while it is still busy with one, only the latest is kept: it says
// where things stand.
TunnelCallback func(TunnelEvent)
// HideClientIP keeps a guest's address out of its forced command's
// SSH_CONNECTION and SSH_CLIENT.
HideClientIP bool
// AutoAccept says the session was started without anyone confirming it
// (--accept). With no AuthorizedKeys as well, it is open: anyone with
// the session ID can join, and nobody was asked. GetSessionResponse.open
// reports that; it changes nothing about who may join.
AutoAccept bool
// FileTransferApprovalRequired says each guest file transfer waits for
// the host's desktop dialog (no --accept). The daemon sets it, with the
// SFTPPermissionChecker that shows the dialog. It is reported to readers
// of the session and changes nothing about what is allowed.
FileTransferApprovalRequired bool
// ProxyURL, when non-nil, routes the connection to the upterm server
// through an HTTP proxy.
ProxyURL *url.URL
PtySize termsize.Size
PinPtySize bool
Term string
// AttachSocketFile is where the local attach door is bound. Like
// AdminSocketFile, supplying it means the caller manages the path and
// no name is claimed; left empty with AdminSocketFile set, no attach
// door is served, which is how an embedder that will never attach a
// terminal says so. Claimed with the name otherwise.
AttachSocketFile string
// AttachListeningCallback is called once the attach socket is bound,
// before the command starts, with the path a client should dial. With
// AwaitInitialClient set, this is the moment to attach.
//
// Called on Run's own goroutine, before the run.Group exists, so it must
// not block: everything after it — the command, the guest door, the
// readiness record — waits behind it.
AttachListeningCallback func(attachSocket string)
// CommandStartedCallback is called once the hosted command is running,
// which with AwaitInitialClient is also the news that a client got
// through the door. A caller whose own attach failed asks this whether
// there is a session to leave alone.
//
// Called on the server's own goroutine, in front of everything the
// command's start releases, so it must not block.
CommandStartedCallback func()
// SessionReadyCallback is called once the session's record has been
// published: the admin socket is bound, the command is running, and the
// record a reader would consult already carries the session ID and the
// status handed to this callback. A caller that tells anyone else the
// session is up says it here, not from CommandStartedCallback — the
// command starting is one of the two facts readiness is made of, and the
// record is written after both. A script that runs `upterm session info`
// the instant it is told "ready" would otherwise be told "starting" by
// the record.
//
// The status is the one the record was written with, which is ready
// unless the tunnel is down by then: reconnecting while the host redials
// it, or disconnected on a relay that cannot take the session back. The
// caller is told what the record says rather than assuming ready, because
// the two agreeing is the whole point of the callback.
//
// Not called when the record could not be published: the run fails
// instead, so that nobody is told about a record that was never written.
// With no session directory — an embedder that supplied its own admin
// socket — there is no record, and the status is the one the session's
// facts give.
//
// Called once, on the readiness actor's own goroutine, after the write;
// it must not block.
SessionReadyCallback func(status string)
// SessionClaimedCallback is called once the session's name is claimed,
// with the directory that holds it, before the tunnel is dialled: the
// first thing a caller can know about a session is its name and its
// paths, and a caller that relays prompts wants them before any prompt.
// Not called when AdminSocketFile was supplied, since nothing is claimed.
//
// Called on Run's own goroutine; it must not block.
SessionClaimedCallback func(*sessiondir.Dir)
// VersionWarningCallback is called when the server's version is
// incompatible with this host's. Nil logs the mismatch and nothing more:
// the daemon has no terminal to print to.
VersionWarningCallback func(*version.CompatibilityResult)
// RelayWarningCallback is called with what the first connection showed
// about the relay that will matter if the tunnel drops: that it can't
// take the session back, or that its certificate doesn't name the host a
// redial would dial. Nil logs it and nothing more, as for
// VersionWarningCallback.
//
// Called at most once, on Run's own goroutine, after
// VersionWarningCallback and before SessionCreatedCallback, so whoever
// prints it prints it ahead of the session; it must not block.
RelayWarningCallback func(RelayWarning)
// AwaitInitialClient defers starting the command until the first host
// client's output subscription is installed, and defers serving guests
// until the command has started. Foreground use sets it: a command that
// exits at once — `upterm host -- false` — would otherwise race the local
// terminal's attach, and lose. Headless use leaves it off.
AwaitInitialClient bool
// InitialClientTimeout bounds that wait; zero means
// internal.DefaultInitialClientTimeout.
InitialClientTimeout time.Duration
// StopGrace bounds each step of the command's teardown; zero means
// internal.DefaultStopGrace.
StopGrace time.Duration
// JoinTimeout bounds the wait for the first guest, starting at readiness.
// Zero waits forever. A running session's timeout can be replaced or
// disabled over the admin socket (`upterm session set`); each replacement
// counts from when it is made. The session enforces it independently of its
// launcher; a guest joining disarms it permanently, even after that guest
// leaves.
JoinTimeout time.Duration
// SFTP configuration
SFTPDisabled bool // Disable SFTP subsystem entirely (--no-sftp)
SFTPPermissionChecker sftp.PermissionChecker // Optional: prompts user for SFTP permissions (nil = auto-allow)
// Name is the session's local name. It determines the socket paths, so
// they are known before the server is ever contacted. It is unrelated to
// the server-assigned session ID in the connect string.
//
// Ignored when AdminSocketFile is set: supplying a socket is how a caller
// says it is managing the paths itself, so Run claims no name and there is
// nothing for this to name. SessionDir stays nil in that case, and no
// record is published.
Name string
// ClaimTimeout bounds how long Run waits for the session registry when it
// claims its name. Zero uses the package's ClaimTimeout; any other value is
// used as it is, so zero or less than zero in the package's, or less than
// zero here, gives the claim no time to wait for a held registry lock.
ClaimTimeout time.Duration
// SessionDir is claimed by Run and readable for as long as Run is
// running. Run clears it on the way out: the directory is released by
// then, a released Dir may not be touched again, and leaving it here
// would be leaving a handle to a name that now belongs to whoever claimed
// it next. Nil when AdminSocketFile was supplied, which is how tests
// drive Host without taking a name.
SessionDir *sessiondir.Dir
// contains filtered or unexported fields
}
func (*Host) JoinState ¶ added in v0.32.0
JoinState reports the running session's join timeout as its daemon holds it, for a caller reporting readiness; nil when Run is not running.
func (*Host) Run ¶
Run hosts one session and returns when it ends.
It may be called again afterwards: everything Run claims, it gives back before returning, including the two fields it fills in on the Host itself. A caller that supplied AdminSocketFile keeps it across runs, since managing the path is what supplying it means.
type KnownHosts ¶ added in v0.37.0
type KnownHosts struct {
File string
// Stdout takes the prompt and the "Permanently added" warning.
Stdout io.Writer
// Proxied suppresses the peer address in the prompt, because through a
// tunnel it belongs to the proxy rather than to the server.
Proxied bool
}
KnownHosts is a known_hosts file and the three steps of trusting a relay's host key against it: Check, Confirm and Record. The callbacks that `upterm host` hands to its tunnel are those steps composed; a caller with no connection open can use them one at a time.
func (KnownHosts) Check ¶ added in v0.37.0
Check never prompts and never writes. A missing file, or a missing directory, is an empty trust store. It returns nil when a key line or an @cert-authority line trusts key, an error wrapping ErrUnknownHostKey when no line names it, and an error wrapping ErrHostKeyChanged when a line for hostname names a different key. A certificate that no @cert-authority line trusts is checked by its own key, once its signer is found not revoked. Anything else is as knownhosts returns it.
func (KnownHosts) Confirm ¶ added in v0.37.0
func (k KnownHosts) Confirm(ctx context.Context, in io.Reader, hostname string, remote net.Addr, key ssh.PublicKey) (bool, error)
Confirm prints the prompt and reads the answer from in, which is "yes", the key's fingerprint or "no"; anything else asks again. It returns true after recording the key, and false for "no". It returns (false, ctx.Err()) as soon as ctx ends, and records nothing once it has: a ctx that is already done gets no prompt and no read.
Each line is read a byte at a time, on a goroutine of its own, so that nothing typed after the answer is consumed. A read that is still blocked when ctx ends is abandoned rather than interrupted: a terminal read cannot be cancelled, and ctx ending means the process is.
func (KnownHosts) Record ¶ added in v0.37.0
Record appends hostname's line to the file, first creating the file and its directory (0700) if they don't exist, and ending the file's last line if it has no newline. A certificate's signing key is recorded as an @cert-authority line. announce prints the "Permanently added" warning.
type ReconnectTiming ¶ added in v0.35.0
type ReconnectTiming struct {
// PingInterval is how long the tunnel may be silent before it is probed,
// and PingBound how long a probe has to prompt any bytes at all. The
// defaults are 15 s and 15 s.
PingInterval, PingBound time.Duration
// AttemptDeadline is how long one redial may take, from dialling to a
// registered tunnel. The default is 30 s.
AttemptDeadline time.Duration
// FastBase and FastCap shape the fast schedule: the wait doubles from
// FastBase up to FastCap. The defaults are 1 s and 30 s.
FastBase, FastCap time.Duration
// SlowWait is the least wait on the slow schedule, and SlowJitter the most
// that is added to it. The defaults are 5 min and 30 s.
SlowWait, SlowJitter time.Duration
// ResetAfter is how long a tunnel must have been up before losing it starts
// the schedule over, so a relay that keeps dropping the tunnel is not
// redialled at the fast schedule's start each time. The default is 60 s.
ResetAfter time.Duration
}
ReconnectTiming paces the tunnel's liveness and its redials. A field left zero or negative takes its default, so a caller can override one and inherit the rest.
type RelayWarning ¶ added in v0.39.0
type RelayWarning struct {
Kind RelayWarningKind
// Host is the hostname the certificate isn't valid for, for
// CertNotValidForServer; empty otherwise.
Host string
}
RelayWarning is what RelayWarningCallback is told.
type RelayWarningKind ¶ added in v0.39.0
type RelayWarningKind int
RelayWarningKind is what a RelayWarning is about.
const ( // NoReconnect is a relay that can't take a session back: one that // registers sessions under IDs of its own. If the tunnel drops, guests // can't reach the session again until it is restarted. NoReconnect RelayWarningKind = iota // CertNotValidForServer is a relay whose certificate isn't valid for the // host the session dialled, so a redial, which is pinned to it, would be // refused. CertNotValidForServer )
type SignerOptions ¶ added in v0.30.0
type SignerOptions struct {
PrivateKeys []string
// IdentitiesOnly makes PrivateKeys the whole identity set, as OpenSSH's
// IdentitiesOnly does: every entry must resolve to a signer, and no
// other key the agent holds is offered.
IdentitiesOnly bool
// Passphrase is asked for an encrypted key's passphrase. Nil prompts on
// this process's terminal, which a daemon does not have.
Passphrase func(file string) ([]byte, error)
// OnSkip is told about a key file that was skipped and why. Nil is
// silent, as SignersFromFiles always was.
OnSkip func(file string, err error)
}
SignerOptions configures SignersWith.
type TunnelEvent ¶ added in v0.39.0
type TunnelEvent struct {
// Up is false when the tunnel was lost and true when it is back.
Up bool
// CanReconnect, on a loss, says whether this relay lets the host
// reconnect. When it doesn't, the loss is final: guests can't join again
// until the session is restarted.
CanReconnect bool
// RouteChanged, on a return, says the relay registered the session at
// another node or user than before, so the connect string guests use is
// not the one they had.
RouteChanged bool
}
TunnelEvent says that guests could not reach the session through the relay, or that they can again.
type UserRef ¶ added in v0.27.0
type UserRef struct {
Provider string // "" for the raw-URL form
User string
Host string // host[:port] as written; "" means "provider default"
URL string // raw-URL form only: the complete .keys URL
Raw string // the original string, for error messages
Mode CredentialMode
}
UserRef is one parsed --authorized-user value.
func ParseUserRef ¶ added in v0.27.0
ParseUserRef parses a reference of the form provider:user, provider:user@host, or an https:// URL. It performs no I/O.
func (UserRef) Display ¶ added in v0.27.0
Display is the resolved identity used as AuthorizedKey.Comment. It names the host actually contacted, which the verbatim input does not when GH_HOST is in play.
func (UserRef) KeysURL ¶ added in v0.27.0
KeysURL returns the endpoint serving this user's authorized_keys body.
func (UserRef) ResolveHost ¶ added in v0.27.0
ResolveHost returns the host[:port] this reference targets.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
replay
Package replay reconstructs, for a joining terminal, the screen the fan-out's ring drew: it emulates the ring on upterm's fork of x/vt, outside every fan-out lock, and renders what the emulator holds.
|
Package replay reconstructs, for a joining terminal, the screen the fan-out's ring drew: it emulates the ring on upterm's fork of x/vt, outside every fan-out lock, and renders what the emulator holds. |
|
Package sessiondir owns the on-disk identity of a session: which name it holds, where its sockets live, whether the process that claimed it is still alive, and how it ended.
|
Package sessiondir owns the on-disk identity of a session: which name it holds, where its sockets live, whether the process that claimed it is still alive, and how it ended. |