ssh_config

package
v0.0.0-...-752bcdd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 12, 2022 License: GPL-3.0 Imports: 13 Imported by: 0

README

ssh_config

Library for decoding/encoding OpenBSD OpenSSH ssh_config files.

Designed so decode's input is the same as same content's encode output. This means that you can change a value in a config file while keeping comments and newlines.

Behaviour to look out for

However, there are many catches:

Backslash transformations

upstream: ErrWarnSingleBackslashTransformed:

any backslashes, where the next char is not \, ', "; an extra backslash is added/seen/read.

2 backslashes are parsed as 2 backslashes: Hostname foo\\bar == Hostname foo\bar in a config literally means SSH will connect to foo\\bar, not foo\bar, or foober.

There are exactly 0 ways to express a single backslash as a value.

Automatic quoting

On encoding, if a value begins or ends with a space, and is not specified to be quoted, it is quoted with single quotes.

Comment levels

To aid custom configuration (simliar to X- headers), expressed as comments, comments may be either in a root (TLD) or a sub (keyword / children) section.

On reading/writing, comments may either be root object, or a child of an another TLD (Host or Match).

Comments and newlines are child objects until the last non-comment key on the (root) tree, where they change to root objects on the first newline.
See layer1b_test.go for an example. There basic schema is here as well:

# C1 (root)

# C2 (root)
Host foo (root)
  KVx (sub)
  # C3 (sub)
       (TBD, result: sub)
  # C4 (sub)
  KVx  (sub)
  # C5 (sub)
       (TBD, result: root)
# C6 !deep
     !deep
# C7 !deep
Hostx deep
Comments and newlines

Comments in ssh_config are defined as empty lines || space after an unquoted # character.

  • # hello in ssh_config is under .Comment as hello (mind the space)
  • Hostname foo #, # will be trimmed, while Hostname foo # Comment =
    • #\n will be trimmed to \n.
  • A space between a KV and a comment will always be inserted. (key value #comment, not key value#comment)
Indenting

Encoding: Indenting is currently soft-coded to 2 spaces. Indentation is used for sub-objects.

Status

tl;dr: pivoting, no typing support planned.


Frankly, it is a headache to do ssh_config with typing in go. I see multiple paths, yet none can keep metadata gracefully.

I want to do:

Keywords.Hostname = "hello"
Keywords.Hostname.Comment = " world"

I can't. There is no root value.

I'd be fine with Keywords.Hostname.Value, but then everything in types_keywords.go would have to have a custom type: instead of:

type Keyword struct {
	HashKnownHosts                   *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	HostbasedAuthentication          *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	IdentitiesOnly                   *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
}

It'd be:

type Keyword struct {
	HashKnownHosts                   *HasKnownHosts `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	HostbasedAuthentication          *HostbasedAuthentication `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	IdentitiesOnly                   *IdentitiesOnly `minArgs:"1" maxArgs:"-2" definition:"Flag"`
}

type HashKnownHosts struct {
    Value bool
    Comment *string
    EncodingKVSeperatorIsEquals bool
}
type HostbasedAuthentication struct {
    Value bool
    Comment *string
    EncodingKVSeperatorIsEquals bool
}
type IdentitiesOnly struct {
    Value bool
    Comment *string
    EncodingKVSeperatorIsEquals bool
}

I just want to say:

type Keyword struct {
	HashKnownHosts                   *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	HostbasedAuthentication          *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	IdentitiesOnly                   *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
}
type Keyword.* struct {
    Comment *string
    EncodingKVSeperatorIsEquals *bool
}

Using a map with metadata, and adding methods to each and every one would also be an option, yet it has the same drawbacks as the first option, and if not using path, it mixes up metadata of same-named keys.

Unimplemented niceties

Updates without re-writing the whole file are possible, but not implemented. They will not be implemented by the maintainer.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidKeyword                 = errors.New("invalid keyword")
	ErrInvalidValue                   = errors.New("invalid value")
	ErrSingleValueOnly                = errors.New("must have exactly 1 value")
	ErrInvalidQuoting                 = errors.New("bad quoting") // TODO: add more info?
	ErrWarnSingleBackslashTransformed = errors.New("1 or more single backslashes changed to 2 backslashes since OpenSSH ssh_config does this (this always happens: st\\ring → st\\\\ring)")
	ErrValidSubkeyAfterXRoot          = errors.New("non-root non-xkeys are not allowed after a root xkey until the next root non-xkey")
	ErrNotImplemented                 = errors.New("not implemented")
)

Functions

func Encode

func Encode(o Opts, cfg []RawTopLevel, data io.Writer) (err error)

Encode from ssh_config to Config

func EncodeValue

func EncodeValue(values []RawValue, comment string) (encoded string, err error)

encodes an ssh_config valuepart if string begins or ends with space, it is automatically quoted without warning

does not perform type checking

possible errors: nil, errWarnSingleBackslashTransformed

func HostMatches

func HostMatches(raw []string, search string) (matches bool)

if any ! matches, return false jfyi Host hello,world foo is "hello,world", "foo"

func MatchMatches

func MatchMatches(raw []string, search string) bool

Types

type AddressFamily

type AddressFamily string // enum: "inet", "inet6", "any"

#### enums ####

type CanonicalizeCNAMEs

type CanonicalizeCNAMEs struct {
	// contains filtered or unexported fields
}

native structs

type Cipher

type Cipher struct {
	// contains filtered or unexported fields
}

type Config

type Config struct {
	// contains filtered or unexported fields
}

func OpenConfig

func OpenConfig(o Opts, name string) (*Config, bool, error)

Opens a config. Changes must be flushed with (*Config).Write(). Filehandle is not kept open after reads and writes.

bool: new file created

func (*Config) GID_PreappendInclude

func (c *Config) GID_PreappendInclude(i string)

WARN: made _only_ for git-id, may break

func (*Config) GID_PreappendRootComment

func (c *Config) GID_PreappendRootComment(s string)

WARN: made _only_ for git-id, may break

func (*Config) GID_RootObjectRemoveFirst

func (c *Config) GID_RootObjectRemoveFirst(key string, values []string) (ok bool)

WARN: made _only_ for git-id, may break

func (*Config) GID_RootObjectSetFirst

func (c *Config) GID_RootObjectSetFirst(key string, values []string, firstValueIsSubKey bool, childs GitIDCommonChildren)

WARN: made _only_ for git-id, may break Brutal implementation of override and don't care anything for the sake of time

func (*Config) GID_RootObjects

func (c *Config) GID_RootObjects(key string, values []string, suffix bool) (matches int, trees []GIDTree)

WARN: made _only_ for git-id, may break suffix: value is handled as a suffix

func (*Config) Write

func (c *Config) Write() error

type ControlPersist

type ControlPersist string // bool or time.Duration

#### custom types

type DynamicForward

type DynamicForward struct {
	// contains filtered or unexported fields
}

type Forward

type Forward string

type ForwardAgent

type ForwardAgent string // "false", "true" is treated as bools

#### custom types

type GIDTree

type GIDTree struct {
	Values   []string
	Children GitIDCommonChildren
}

WARN: made _only_ for git-id, may break

type GitIDCommonChildren

type GitIDCommonChildren struct {
	IdentitiesOnly bool
	IdentityFile, Hostname, XDescription,
	XGitConfigUsername, XGitConfigUserEmail, XGitConfigSigningKey,
	XParent string
}

type Hash

type Hash string // enum: "md5", "sha256"

#### enums ####

type Ipqos

type Ipqos struct {
	// contains filtered or unexported fields
}

#### custom types

type Keywords

type Keywords struct {

	// ##### native types #####
	CanonicalizeHostname             *bool `minArgs:"1" maxArgs:"1" definition:"CanonicalizeHostname"`
	Compression                      *bool `minArgs:"1" maxArgs:"1" definition:"Compression"`
	ControlMaster                    *bool `minArgs:"1" maxArgs:"1" definition:"ControlMaster"`
	KbdInteractiveAuthentication     *bool `minArgs:"1" maxArgs:"1" definition:"Flag" aliases:"ChallengeResponseAuthentication,TISAuthentication"`
	PubkeyAuthentication             *bool `minArgs:"1" maxArgs:"1" definition:"Flag" aliases:"DSAAuthentication"`
	BatchMode                        *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	CanonicalizeFallbackLocal        *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	CheckHostIP                      *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	ClearAllForwardings              *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	EnableSSHKeysign                 *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	ExitOnForwardFailure             *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	ForkAfterAuthentication          *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	ForwardX11                       *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	ForwardX11Trusted                *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	GatewayPorts                     *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	GssAuthentication                *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	GssDelegateCreds                 *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	HashKnownHosts                   *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	HostbasedAuthentication          *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	IdentitiesOnly                   *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	NoHostAuthenticationForLocalhost *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	PasswordAuthentication           *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	PermitLocalCommand               *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	ProxyUseFdpass                   *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	StdinNull                        *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	StreamLocalBindUnlink            *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	TCPKeepAlive                     *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	VisualHostKey                    *bool `minArgs:"1" maxArgs:"-2" definition:"Flag"`
	RequestTTY                       *bool `minArgs:"1" maxArgs:"-2" definition:"RequestTTY"`
	StrictHostKeyChecking            *bool `minArgs:"1" maxArgs:"-2" definition:"StrictHostkey"`
	Tunnel                           *bool `minArgs:"1" maxArgs:"-2" definition:"Tunnel"`
	// definition csvStringSlice: all slice items are in ssh_config[0] (len == 1), seperated by comma
	GlobalKnownHostsFile     *[]string `minArgs:"1" maxArgs:"-2" definition:"csvStringSlice"`
	IgnoreUnknown            *[]string `minArgs:"1" maxArgs:"-2" definition:"csvStringSlice"`
	KbdInteractiveDevices    *[]string `minArgs:"1" maxArgs:"-2" definition:"csvStringSlice"`
	PreferredAuthentications *[]string `minArgs:"1" maxArgs:"-2" definition:"csvStringSlice"`
	UserKnownHostsFile       *[]string `minArgs:"1" maxArgs:"-2" definition:"csvStringSlice"`
	// definition canonicalizeCNAMEs: csvStringSlice where each set is 2tuplet x:y
	CanonicalizePermittedCNAMEs *CanonicalizeCNAMEs `minArgs:"1" maxArgs:"-2" definition:"canonicalizeCNAMEs"`
	/* definition duration Format is a sequence of:
	*      time[qualifier]...
	*
	* Valid time qualifiers are:
	*      <none>  seconds
	*      s|S     seconds
	*      m|M     minutes
	*      h|H     hours
	*      d|D     days
	*      w|W     weeks
	* Examples:
	*      90m     90 minutes
	*      1h30m   90 minutes
	 */
	ConnectTimeout    *time.Duration `minArgs:"1" maxArgs:"-2" definition:"duration"`
	ForwardX11Timeout *time.Duration `minArgs:"1" maxArgs:"-2" definition:"duration"`
	// definition dynamicForward: [host:]port, may have [ipv6]
	DynamicForward *DynamicForward `minArgs:"1" maxArgs:"-2" definition:"dynamicForward"`
	// definition indifferentString Key="echo" "hi" are joined to "echo hi" on parse
	KnownHostsCommand *string `minArgs:"1" maxArgs:"-2" definition:"indifferentString"`
	LocalCommand      *string `minArgs:"1" maxArgs:"-2" definition:"indifferentString"`
	ProxyCommand      *string `minArgs:"1" maxArgs:"-2" definition:"indifferentString"`
	RemoteCommand     *string `minArgs:"1" maxArgs:"-2" definition:"indifferentString"`
	// definition permoctal: 0777 (4 digits in base8)
	StreamLocalBindMask *int `minArgs:"1" maxArgs:"-2" definition:"permoctal"` // 0777
	/* definition rekeyLimit: 1st: "default" or int[qualifier], qualifier:K/M/G; 2nd (optional): duration (or 'none')
	* 1st: 1..15: RekeyLimit too small */
	RekeyLimit *RekeyLimit `minArgs:"1" maxArgs:"-2" definition:"rekeyLimit"`
	// stringSlice: slice in go, slice in conf
	CanonicalDomains *[]string `minArgs:"1" maxArgs:"-2" definition:"stringSlice"`
	Include          *[]string `minArgs:"1" maxArgs:"-1" definition:"stringSlice"`
	LogVerbose       *[]string `minArgs:"1" maxArgs:"-2" definition:"stringSlice"`
	SendEnv          *[]string `minArgs:"1" maxArgs:"-2" definition:"stringSlice"`
	SetEnv           *[]string `minArgs:"1" maxArgs:"-2" definition:"stringSlice"`
	// definition multiDefineStringSlice: specifying key-value multiple times as a way of expressing slice
	CertificateFile *[]string `minArgs:"1" maxArgs:"-2" definition:"multiDefineStringSlice"`
	IdentityFile    *[]string `minArgs:"1" maxArgs:"-2" definition:"multiDefineStringSlice"`
	// definition tunnelDevice: local_tun[:remote_tun]
	TunnelDevice TunnelDevice `minArgs:"1" maxArgs:"-2" definition:"tunnelDevice"`
	// definition string: also includes keywords where type checking isn't possible outside of config time of use
	BindAddress         *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	BindInterface       *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	ControlPath         *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	EscapeChar          *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	HostKeyAlias        *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	Hostname            *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	IdentityAgent       *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	PKCS11Provider      *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	RevokedHostKeys     *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	SecurityKeyProvider *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	User                *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	XAuthLocation       *string `minArgs:"1" maxArgs:"-2" definition:"string"`
	Port                *uint16 `minArgs:"1" maxArgs:"-2" definition:"uint16"`

	// ##### enums #####
	AddressFamily    *AddressFamily   `minArgs:"1" maxArgs:"-2" definition:"AddressFamily"`
	FingerprintHash  *Hash            `minArgs:"1" maxArgs:"-2" definition:"Hash"`
	LogFacility      *LogFacility     `minArgs:"1" maxArgs:"-2" definition:"LogFacility"`
	LogLevel         *LogLevel        `minArgs:"1" maxArgs:"-2" definition:"LogLevel"`
	SessionType      *SessionType     `minArgs:"1" maxArgs:"-2" definition:"SessionType"`
	UpdateHostkeys   *YesNoAsk        `minArgs:"1" maxArgs:"-2" definition:"YesNoAsk"`
	VerifyHostKeyDNS *YesNoAsk        `minArgs:"1" maxArgs:"-2" definition:"YesNoAsk"`
	AddKeysToAgent   *YesNoAskConfirm `minArgs:"1" maxArgs:"-2" definition:"YesNoAskConfirm"`
	/* definition csvStringSlice, but begins with "" (set/override), + (append), ^ (preappend), - (subtract regex)
	*  - supports wildtags (*), NEEDINFO:{-2, -2, are wildcards supported on set/additions?
	* ciphers shall not be enummed, as they are independent of the config, and change often */
	CASignatureAlgorithms       *Cipher `minArgs:"1" maxArgs:"-2" definition:"cipher"`
	Ciphers                     *Cipher `minArgs:"1" maxArgs:"-2" definition:"cipher"`
	HostbasedAcceptedAlgorithms *Cipher `minArgs:"1" maxArgs:"-2" definition:"cipher"`
	HostKeyAlgorithms           *Cipher `minArgs:"1" maxArgs:"-2" definition:"cipher"`
	KexAlgorithms               *Cipher `minArgs:"1" maxArgs:"-2" definition:"cipher"`
	PubkeyAcceptedAlgorithms    *Cipher `minArgs:"1" maxArgs:"-2" definition:"cipher"`
	// definition permitRemoteOpen: none / any / host:port / :port
	PermitRemoteOpen *PermitRemoteOpen `minArgs:"1" maxArgs:"-2" definition:"permitRemoteOpen"`

	// ##### custom types #####
	// definition boolString: bool or string
	ForwardAgent *ForwardAgent `minArgs:"1" maxArgs:"-2" definition:"boolString"`
	// definition controlPersist: Flag or duration
	ControlPersist *ControlPersist `minArgs:"1" maxArgs:"-2" definition:"controlPersist"`
	/* definition: Accepted values are af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43,
	* cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, ef, le, lowdelay, throughput, reliability,
	* a numeric value, or none to use the operating system default. */
	IPQoS *Ipqos `minArgs:"1" maxArgs:"2" definition:"ipqos"`
	// definition nzint32: non-zero int32:{-2, -2, 0..0x7fffffff (2147483647)
	CanonicalizeMaxDots     *Nzint32 `minArgs:"1" maxArgs:"1" definition:"nzint32"`
	ConnectionAttempts      *Nzint32 `minArgs:"1" maxArgs:"1" definition:"nzint32"`
	NumberOfPasswordPrompts *Nzint32 `minArgs:"1" maxArgs:"1" definition:"nzint32"`
	ServerAliveCountMax     *Nzint32 `minArgs:"1" maxArgs:"1" definition:"nzint32"`
	ServerAliveInterval     *Nzint32 `minArgs:"1" maxArgs:"1" definition:"nzint32"`
	/* definition forward:
	* dynamicfwd == 0
	 *   [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
	 *   listenpath:connectpath
	 * dynamicfwd == 1
	 *	[listenhost:]listenport */
	LocalForward  *Forward `minArgs:"1" maxArgs:"-2" definition:"forward"` // type checking very hard, falling back to string for now
	RemoteForward *Forward `minArgs:"1" maxArgs:"-2" definition:"forward"`

	// ##### not availiable ##### (treated as string)
	// definition deprecated: deprecated by OpenSSH, maybe return friendly error?
	Cipher                *string `minArgs:"1" maxArgs:"-2" definition:"deprecated"`
	FallbackToRsh         *string `minArgs:"1" maxArgs:"-2" definition:"deprecated"`
	GlobalKnownHostsFile2 *string `minArgs:"1" maxArgs:"-2" definition:"deprecated"`
	RhostsAuthentication  *string `minArgs:"1" maxArgs:"-2" definition:"deprecated"`
	UsePrivilegedPort     *string `minArgs:"1" maxArgs:"-2" definition:"deprecated"`
	UserKnownHostsFile2   *string `minArgs:"1" maxArgs:"-2" definition:"deprecated"`
	UseRoaming            *string `minArgs:"1" maxArgs:"-2" definition:"deprecated"`
	UseRsh                *string `minArgs:"1" maxArgs:"-2" definition:"deprecated"`
	// definition deprecatedHidden: no friendly error :(
	Protocol *string `minArgs:"1" maxArgs:"-2" definition:"deprecatedHidden"`
	// unsupported by OpenSSH, maybe return friendly error
	AFSTokenPassing         *string `minArgs:"1" maxArgs:"-2" definition:"unsupported"`
	CompressionLevel        *string `minArgs:"1" maxArgs:"-2" definition:"unsupported"`
	KerberosAuthentication  *string `minArgs:"1" maxArgs:"-2" definition:"unsupported"`
	KerberosTGTPassing      *string `minArgs:"1" maxArgs:"-2" definition:"unsupported"`
	RhostsRSAAuthentication *string `minArgs:"1" maxArgs:"-2" definition:"unsupported"`
	RSAAuthentication       *string `minArgs:"1" maxArgs:"-2" definition:"unsupported"`
}

https://ftp.openbsd.org/pub/OpenBSD/OpenSSH/openssh-8.8.tar.gz readconf.c#984: switch (opcode) {

type LogFacility

type LogFacility string // enum: "daemon", "user", "auth", "local0", "local1", "local2", "local3", "local4", "local5", "local6", "local7"

#### enums ####

type LogLevel

type LogLevel string // enum: "quiet", "fatal", "error", "info", "verbose", "debug", "debug1", "debug2", "debug3"

#### enums ####

type Nzint32

type Nzint32 int32 // must not be negative

type Opts

type Opts struct {

	// valid root-level xkeys, at root level they have no parent
	RootXKeys map[string]bool // bool: may have children xkeys

	// valid children xkeys, housed under a root/parent (x)key
	SubXKeys []string

	// Indentation to use when encoding
	Indent string // standard: "  "
}

type PermitRemoteOpen

type PermitRemoteOpen struct {
	// contains filtered or unexported fields
}

type RawKeyword

type RawKeyword struct {
	Key    string
	Values []RawValue // when key set, len(Values) >= 1
	// "# foobar" → " foobar", note the leading space
	Comment string // at the end of same line as Key

	EncodingKVSeperatorIsEquals bool // "Key=Value" instead of "Key Value"
}

type RawTopLevel

type RawTopLevel struct {
	Key string // enum(4): "" (comment / empty line), Host, Match,
	//                     Include: not recursed, nothing is done (no Children)
	Values []RawValue
	// "# foobar" → " foobar", note the leading space
	Comment                     string
	EncodingKVSeperatorIsEquals bool // "Key=Value" instead of "Key Value"

	Children []RawKeyword
}

func Decode

func Decode(o Opts, data io.Reader) ([]RawTopLevel, error)

Decode from ssh_config to Config.

Host, Match and Include are hardcoded since there are only 3, and Include means different things in different contexts.

func RootBySubKV

func RootBySubKV(cfg []RawTopLevel, rootKey, subKey string, subValue []string) (scfg []RawTopLevel)

get all roots what have defined KV under them

type RawValue

type RawValue struct {
	Value  string
	Quoted int // enum: 0: not, 1: single, 2: double
}

func DecodeValue

func DecodeValue(s string) (strings []RawValue, comment string, _ error)

decodes an ssh_config valuepart does not know of types

possible errors: nil, errInvalidQuoting

type RekeyLimit

type RekeyLimit struct {
	// contains filtered or unexported fields
}

type RootWords

type RootWords struct {
	Host    *[]string `minArgs:"1" maxArgs:"-2" definition:"stringSlice"`
	Match   *[]string `minArgs:"1" maxArgs:"-2" definition:"match"` // [] of string=csvStringSlice, or string (key only)
	Include *[]string `minArgs:"1" maxArgs:"-2" definition:"stringSlice"`
}

for sake of documentation

type SessionType

type SessionType string // enum: "none", "subsystem", "default"

#### enums ####

type TunnelDevice

type TunnelDevice struct {
	// contains filtered or unexported fields
}

type YesNoAsk

type YesNoAsk string // enum: "false", "true", "ask"

#### enums ####

type YesNoAskConfirm

type YesNoAskConfirm string // enum: "false", "true", "ask", "confirm"

#### enums ####

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL