update... work pending

This commit is contained in:
brent saner
2025-02-04 12:14:08 -05:00
parent 3b4d712722
commit 3c984a0636
39 changed files with 2122 additions and 597 deletions

View File

@@ -1,19 +1,7 @@
{
"default_username": "default_user",
"freq": "5m",
"1tun": true,
"cache_db": "/var/cache/gobroke.db",
"cache_perms": {
"file": {
"user": "",
"group": "",
"mode": 384
},
"dir": {
"user": "",
"group": "",
"mode": 448
}
},
"tunnels": [
{
"tun_id": 123,

View File

@@ -1,189 +1,15 @@
# This file is heavily commented explaining various configuration options.
# The other configuration file examples are uncommented, but their field names
# should be easily visually mapped to the ones in here.
# All example configuration files evaluate to the same configuration.
# The test_uncommented.toml file is the exact same is this but without
# empty newlines and comments.
# DefaultUsername specifies the default username to use for
# authenticating to tunnelbroker.net.
# It is optional, as the username can be specified for each Tunnel,
# but at least one or the other *must* be provided.
# This makes it easier if you have multiple tunnels under the same account
# (as possible in higher levels of HE IPv6 certification).
# If a username is specified in Tunnel.Username, it will be used.
# If not (and, of course, DefaultUsername is specified), then
# DefaultUsername will be used for that Tunnel.
DefaultUsername = "default_user"
# If SingleTunnel is true, each Tunnel below will be run in order instead of
# concurrently.
# If there is any concern about race conditions (e.g. the same service being
# restarted by multiple tunnels, etc.), then it is HIGHLY RECOMMENDED
# you set this to true.
DefaultUsername = 'default_user'
Frequency = '5m'
SingleTunnel = true
# CacheDbPath is entirely optional.
# If not provided, results will be cached in RAM (and thus lost on reboot
# or program termination/restart).
# (This can be explicitly specified by using the value ':memory:'.)
# If provided, it should be a path to a file to use as a SQLite3 database
# that holds cached information.
# The information that is cached contains only:
# * each Tunnel.TunnelID
# * the associated tunnelbroker.FetchedTunnel
# * a CRC32 of all configuration (as defined in this file) for that Tunnel
# The UpdateKey and other configuration defined here (aside from
# Tunnel.TunnelID, and Tunnel.ExplicitClientIP if specified) are
# NOT stored.
# Any tunnel present in a persistent cache DB but *not* defined in the
# running GoBroke config will be removed.
# Note that the cache DB primary key is based on the Tunnel.TunnelID,
# as one cannot define multiple client endpoints for the same tunnel.
CacheDbPath = '/var/cache/gobroke.db'
# CacheDbPerms specify the permissions for CacheDbPath.
# This directive is completely optional, and is
# ignored if CacheDbPath is ":memory:" (or unspecified).
# If not specified (and CacheDbPath is persistent),
# then the runtime user's umask and effective UID/GID
# is used if creating a new database file.
# If the file exists and permissions are defined, they will
# be enforced.
# If the file exists but no permissions are defined, they
# will be left as-is.
[CacheDbPerms]
# Permissions are/may be defined for both the file being written
# and the parent directory (see below).
[CacheDbPerms.File]
# The User is optional.
# If specified as '-1', the owner will not be modified/enforced.
# If specified as an empty string (the default), the runtime EUID is enforced.
# Otherwise, it may be a username or a UID (checked in that order).
# (For new files/directories, the OS default behavior is used.)
User = ""
# Group is also optional, and follows the same exact logic as User except
# for EGID/groupnames/GIDs.
Group = ""
# Mode is optional also.
# It *must* be equal to the octal mode bits (e.g. it must be an
# unsigned integer 0-4095), but may be represented in multiple ways.
# e.g.:
# Mode = 0o0600
# Mode = 0o600
# Mode = 0x0180
# Mode = 0x180
# Mode = 0b110000000
# Mode = 384
# All evaluate to the exact same value in TOML:
# https://toml.io/en/v1.0.0#integer
# For consistency with `chmod(1)`, it is recommended to use the
# octal representation (0o0600 or 0o600 above).
# If you need help determining what number you should actually use,
# you can use the calculator here:
# https://rubendougall.co.uk/projects/permissions-calculator/
# (source: https://github.com/Ruben9922/permissions-calculator )
# (Supports/includes "special" bits)
# or here:
# https://wintelguy.com/permissions-calc.pl
# (beware of ads)
# (provides an explanation of the bits)
# Or see https://en.wikipedia.org/wiki/Chmod
# Note that this does, technically, work on Windows but only read vs. read-write
# for the User is used (https://pkg.go.dev/os?GOOS=windows#Chmod).
# If not specified, the default is 0o0600 for files and 0o0700 for directories.
Mode = 0o0600
# Dir permissions specifiy permissions/ownership of the parent directory of the cache DB.
# The same rules, logic, behavior, etc. as in CacheDbPerms.File apply here.
[CacheDbPerms.Dir]
User = ""
Group = ""
Mode = 0o0700
#############
## Tunnels ##
#############
# Each Tunnel represents a single tunnelbroker.net tunnel configuration.
# Note that each Tunnel is run concurrently. If this is undesired due to
# potential race conditions, set the root-level directive SingleTunnel
# to true.
[[Tunnel]]
# The TunnelID can be found by logging into https://tunnelbroker.net/ and,
# at the "Main Page" that loads when logging in, clicking on the desired
# tunnel name.
# The tunnel ID is then displayed in both the URL bar:
# https://tunnelbroker.net/tunnel_detail.php?tid=<TunnelID>
# And as the first line on the first tab ("IPv6 Tunnel" tab),
# labeled "Tunnel ID".
TunnelID = 123
# If you wish to use a different or explicit "Client IPv4 address",
# this can be specified via ExplicitClientIP.
# If it is empty or is not specified, the public IP of this host will be determined
# via an external service.
# This *must* be an IPv4 address (if specified).
ExplicitClientIP = '203.0.113.1'
# If you have specified a custom MTU under the "Advanced" tab for this tunnel,
# you can set this value here.
# If you have not set a custom one, leave this option unspecified;
# the default (and maximum allowed), 1480 MTU, will be used in that case.
MTU = 1450
# The Username field is optional IF DefaultUsername was specified.
# This also allows you to specify tunnels from different accounts
# by providing a tunnel-specific username.
Username = "specific_user"
# The UpdateKey can be found under the "Advanced" tab on your tunnelbroker.net
# tunnel's page, labeled "Update Key".
# Your real token is likely to be a bit longer and more random.
# This token is used to not only update the client-side tunnel IP but also to
# query the HE Tunnelbroker "API" (it's really just a single endpoint)
# to get the tunnel configuration.
UpdateKey = "abcdef"
######################
## Config Templates ##
######################
# Each ConfigTemplate consists of a path to a template file and a destination
# file at the bere minimum. In addition, Commands may be provided.
# Any paths leading up to Destination that don't exist will (attempt to be)
# created.
# The template is always rendered in memory, but the destination is only written
# if:
# * The Destination doesn't exist
# * The Destination differs from the buffered rendering of the template
# Commands are optional, and are a list of commands to be run.
# Their running may be restricted to only if the tunnel information/IP
# information has changed, always run, or the inverse of all conditions.
[[Tunnel.ConfigTemplate]]
# Template points to where the template file can be found.
# It must be in a Golang text/template syntax/format; see:
# https://pkg.go.dev/text/template
# Refer to the library's definition of the tunnelbroker.FetchedTunnel struct;
# this is the object that is passed to the template.
Template = "/etc/gobroke/tpl/dnsmasq/ra_dhcpv6.conf.tpl"
# Destination is the file to write to.
# It will only be written to if:
# * The path does not exist
# * The path exists but is different from the in-memory rendered buffer
# An attempt will be made to create any leading components that are not
# present.
# It is recommended to enforce permissions/ownership of these via the
# Commands.
Destination = "/etc/dnsmasq.d/ra_dhcpv6.conf"
#################################
## Config Template Permissions ##
#################################
# Permissions can be defined for the Destionation file.
# They are completely optional, in which case the default umask, user,
# group, etc. for the runtime user will be used, and permissions/ownership
# will not be enforced for existing Destination files.
# It follows the same syntax, logic, behavior, etc. as CacheDbPerms.
[[Tunnel.ConfigTemplate.Permissions]]
[[Tunnel.ConfigTemplate.Permissions.File]]
User = ""
@@ -193,108 +19,30 @@ CacheDbPath = '/var/cache/gobroke.db'
User = ""
Group = ""
Mode = 0o0700
##############################
## Config Template Commands ##
##############################
# Commands are a collection of commands to run as part of this template
# run.
# Multiple Commands may be specified; they will be run in the order specified.
# The below Command would be equivalent to:
# SOMEENV=SOMEVAL /usr/local/bin/somecmd -f foo
# on the shell.
[[Tunnel.ConfigTemplate.Command]]
# ProgramPath should be the absolute path to the binary to run.
# It behaves as an (os/)exec.Cmd.Path (https://pkg.go.dev/os/exec#Cmd),
# It is recommended to use an absolute path.
ProgramPath = '/usr/local/bin/somecmd'
# Args are optional for a Command.
# They should conform to the rules for (os/)exec.Cmd.Args.
Args = [
'-f', 'foo',
]
# If IsolatedEnv is false (the default), the runtime environment variables
# will be applied to the command.
# If true, *only* the EnvVars, if specified, will be used for the spawned
# command (an empty environment will be used if IsolateEnv is true and
# no EnvVars are specified).
IsolatedEnv = false
# If provided, EnvVars can be used to add/replace environment variables.
# They should conform to the rules for (os/)exec.Cmd.Env.
# Whether they are added to/selectively replace or completely replace
# the current runtime environment variables depends on how IsolateEnv
# is configured.
EnvVars = [
'SOMEENV=SOMEVAL',
]
# If OnChange is true, this Command will run *only if SOMETHING CHANGED*.
# (e.g. a /48 was added to the tunnel, the client IP is different, etc.)
# If false, this Command will run *only if NOTHING CHANGED*.
# If unspecified, the default is to always run this command regardless
# of change status.
# The very first (successful) run of a Tunnel is considered a "change",
# as is writing out this template to disk as a new file.
OnChange = true
# By default, this Command will be run literally/as-is.
# However, in some cases it may be useful to dynamically template out
# commands to run.
# If IsTemplate is set to true, then this Command.ProgramPath, each
# of the Command.Args, and each of the Command.EnvVars will be
# treated as Golang text/template strings as well, and will also
# be passed a tunnelbroker.FetchedTunnel.
# Note that if IsolateEnv is false, runtime/inherited environment
# variables will *not* be templated.
# It is recommended to not enable this unless necessary as it can add
# a non-negligible amount of resource overhead/execution time.
IsTemplate = false
#######################################################################
# Multiple ConfigTemplates may be specified.
[[Tunnel.ConfigTemplate]]
Template = "/etc/gobroke/tpl/stat.tpl"
Destination = "/tmp/gobroke.dump"
#####################
## Tunnel Commands ##
#####################
# Each Tunnel also supports its *own* commands. The syntax, spcification,
# behavior, etc. is the same as the Tunnel.ConfigTemplate.Command.
# These are executed after all Tunnel.ConfigTemplate (if any) are executed.
# This is particularly useful for consolidating service restarts.
[[Tunnel.Command]]
ProgramPath = 'systemctl'
Args = [
'restart',
'someservice',
]
# OnChange in a Tunnel.Command is scoped to any updates of the tunnel
# and any changes in ANY of the Tunnel.ConfigTemplate specified
# for this Tunnel (if true and ConfigTemplate were specified).
OnChange = true
###############################################################################
# Multiple tunnel configurations are supported as well.
[[Tunnel]]
TunnelID = 456
Username = "specific_user"
UpdateKey = "defghi"
######################
## General Commands ##
######################
# Command items may be specified at the root level as well.
# The syntax is like all other Commands items, with two exceptions:
# * There is no templating performed...
# * As such, there is no IsTemplate directive for these.
# A root-level Command is run after all tunnels complete.
# The OnChange directive is true if any Tunnels result in any changes.
[[Command]]
ProgramPath = "/usr/local/bin/alltunpsrogram"

View File

@@ -1,17 +1,6 @@
<!--
See the example TOML for detailed comments and explanations.
-->
<config defaultUser="default_user"
oneTun="true"
cacheDb="/var/cache/gobroke.db">
<cachePerms>
<file user=""
group=""
mode="384"/>
<dir user=""
group=""
mode="448"/>
</cachePerms>
freq="5m"
oneTun="true">
<tunnels>
<tunnel id="123"
addr="203.0.113.1"

View File

@@ -1,19 +1,8 @@
# See the example TOML for detailed comments and explanations.
Default Username: default_user
NoGoTunnel: true
Frequency: 5m
Cache Database Path: /var/cache/gobroke.db
Cache Database Permissions:
File:
User: ''
Group: ''
Mode: 384
Directory:
User: ''
Group: ''
Mode: 448
Single Tunnel: true
Tunnels:
- Tunnel ID: 123

View File

@@ -1,57 +0,0 @@
DefaultUsername = "default_user"
SingleTunnel = true
CacheDbPath = '/var/cache/gobroke.db'
[CacheDbPerms]
[CacheDbPerms.File]
User = ""
Group = ""
Mode = 0o0600
[CacheDbPerms.Dir]
User = ""
Group = ""
Mode = 0o0700
[[Tunnel]]
TunnelID = 123
ExplicitClientIP = '203.0.113.1'
MTU = 1450
Username = "specific_user"
UpdateKey = "abcdef"
[[Tunnel.ConfigTemplate]]
Template = "/etc/gobroke/tpl/dnsmasq/ra_dhcpv6.conf.tpl"
Destination = "/etc/dnsmasq.d/ra_dhcpv6.conf"
[[Tunnel.ConfigTemplate.Permissions]]
[[Tunnel.ConfigTemplate.Permissions.File]]
User = ""
Group = ""
Mode = 0o0600
[[Tunnel.ConfigTemplate.Permissions.Dir]]
User = ""
Group = ""
Mode = 0o0700
[[Tunnel.ConfigTemplate.Command]]
ProgramPath = '/usr/local/bin/somecmd'
Args = [
'-f', 'foo',
]
IsolatedEnv = false
EnvVars = [
'SOMEENV=SOMEVAL',
]
OnChange = true
IsTemplate = false
[[Tunnel.ConfigTemplate]]
Template = "/etc/gobroke/tpl/stat.tpl"
Destination = "/tmp/gobroke.dump"
[[Tunnel.Command]]
ProgramPath = 'systemctl'
Args = [
'restart',
'someservice',
]
OnChange = true
[[Tunnel]]
TunnelID = 456
Username = "specific_user"
UpdateKey = "defghi"
[[Command]]
ProgramPath = "/usr/local/bin/alltunpsrogram"

View File

@@ -2,69 +2,151 @@ package conf
import (
`encoding/json`
`encoding/xml`
`hash`
`os`
"github.com/BurntSushi/toml"
"github.com/creasty/defaults"
"github.com/goccy/go-yaml"
"r00t2.io/sysutils/paths"
`github.com/BurntSushi/toml`
`github.com/creasty/defaults`
`github.com/davecgh/go-spew/spew`
`github.com/goccy/go-yaml`
`github.com/zeebo/blake3`
`r00t2.io/gobroke/tplCmd`
`r00t2.io/goutils/logging`
`r00t2.io/sysutils/paths`
)
// NewConfig returns a conf.Config from filepath path.
func NewConfig(path string) (cfg *Config, err error) {
/*
Checksum guarantees a standard checksum of a configuration.
If you are comparing new vs. old configs, be sure to use this function
and compare against a Config.Checksum() to ensure consistent hashing algorithms etc.
*/
func Checksum(confBytes []byte) (cksum []byte, err error) {
var b []byte
// If built with CGO enabled, this'll take advantage of SIMD.
// Should be fast enough without it, though.
var h hash.Hash = blake3.New()
if err = paths.RealPath(&path); err != nil {
if _, err = h.Write(confBytes); err != nil {
return
}
if cfg, err = NewConfigFromBytes(b); err != nil {
cksum = h.Sum(nil)
return
}
/*
ChecksumPath is a convenience wrapper around Checksum, operating on a filepath instead of bytes.
*/
func ChecksumPath(confPath string) (cksum []byte, err error) {
var b []byte
if err = paths.RealPath(&confPath); err != nil {
return
}
if b, err = os.ReadFile(confPath); err != nil {
return
}
if cksum, err = Checksum(b); err != nil {
return
}
return
}
// NewConfig returns a conf.Config from filepath path.
func NewConfig(path string, debug bool, log logging.Logger) (cfg *Config, err error) {
var b []byte
if log == nil {
log = &logging.NullLogger{}
}
log.Debug("conf.NewConfig: New config from path '%s'", path)
if err = paths.RealPath(&path); err != nil {
log.Err("conf.NewConfig: Received error canonizing config path '%s': %s", path, err)
return
}
log.Debug("conf.NewConfig: Canonized configuration path to '%s'", path)
if cfg, err = NewConfigFromBytes(b, debug, log); err != nil {
log.Err("conf.NewConfig: Received error parsing config '%s': %s", path, err)
return
}
cfg.confPath = new(string)
*cfg.confPath = path
log.Debug("conf.NewConfig: Successfully parsed and loaded configuration '%s'", path)
return
}
// NewConfigFromBytes returns a conf.Config from bytes b. b may be a JSON, TOML, XML, or YAML representation.
func NewConfigFromBytes(b []byte) (cfg *Config, err error) {
func NewConfigFromBytes(b []byte, debug bool, log logging.Logger) (cfg *Config, err error) {
var tplBytes []byte
if b == nil || len(b) == 0 {
return
}
if log == nil {
log = &logging.NullLogger{}
}
log.Debug("conf.NewConfigFromBytes: New config from %d bytes.", len(b))
log.Debug("conf.NewConfigFromBytes: Config before parsing:\n%s", string(b))
if err = json.Unmarshal(b, &cfg); err != nil {
if err = yaml.Unmarshal(b, &cfg); err != nil {
if err = toml.Unmarshal(b, &cfg); err != nil {
if err = xml.Unmarshal(b, &cfg); err != nil {
if err = yaml.Unmarshal(b, &cfg); err != nil {
if err = toml.Unmarshal(b, &cfg); err != nil {
log.Err("conf.NewConfigFromBytes: Unable to parse config as JSON, XML, YAML, or TOML; config invalid.")
err = ErrUnkownSyntax
return
} else {
log.Debug("conf.NewConfigFromBytes: Config parsed as TOML.")
}
} else {
log.Debug("conf.NewConfigFromBytes: Config parsed as YAML.")
}
} else {
log.Debug("conf.NewConfigFromBytes: Config parsed as XML.")
}
} else {
log.Debug("conf.NewConfigFromBytes: Config parsed as JSON.")
}
if err = defaults.Set(cfg); err != nil {
return
}
if cfg.CacheDB != ":memory:" {
if err = paths.RealPath(&cfg.CacheDB); err != nil {
return
}
if cfg.CacheDbPerms == nil {
cfg.CacheDbPerms = new(Perms)
}
if err = cfg.CacheDbPerms.SetMissing(); err != nil {
return
}
}
log.Debug("conf.NewConfigFromBytes: Configuration after parsing and defaults:\n%s", spew.Sdump(cfg))
if err = validate.Struct(cfg); err != nil {
log.Err("conf.NewConfigFromBytes: Config validation failed: %v", err)
return
}
cfg.log = log
cfg.debug = debug
for _, t := range cfg.Tunnels {
if t == nil {
continue
}
t.cfg = cfg
if t.Username == nil {
if cfg.Username == nil {
log.Err(
"conf.NewConfigFromBytes: Username is not provided for tunnel %d and no default username was provided.",
t.TunnelID,
)
err = ErrMissingUser
return
} else {
@@ -73,14 +155,29 @@ func NewConfigFromBytes(b []byte) (cfg *Config, err error) {
}
if t.TemplateConfigs != nil && len(t.TemplateConfigs) > 0 {
for _, tpl := range t.TemplateConfigs {
if tpl == nil {
continue
}
if err = paths.RealPath(&tpl.Template); err != nil {
log.Err("conf.NewConfigFromBytes: Unable to canonize path to template '%s': %s", tpl.Template, err)
return
}
if err = paths.RealPath(&tpl.Dest); err != nil {
log.Err("conf.NewConfigFromBytes: Unable to canonize path to destination '%s': %s", tpl.Dest, err)
return
}
if tplBytes, err = os.ReadFile(tpl.Template); err != nil {
log.Err("conf.NewConfigFromBytes: Unable to read template file '%s': %s", tpl.Template, err)
return
}
tpl.Tpl = tplCmd.GetTpl()
if _, err = tpl.Tpl.Parse(string(tplBytes)); err != nil {
log.Err("conf.NewConfigFromBytes: Unable to parse template file '%s': %s", tpl.Template, err)
return
}
if tpl.Perms != nil {
if err = tpl.Perms.SetMissing(); err != nil {
log.Err("conf.NewConfigFromBytes: Unable to enrich permissions for template '%s': %s", tpl.Template, err)
return
}
}
@@ -88,5 +185,12 @@ func NewConfigFromBytes(b []byte) (cfg *Config, err error) {
}
}
if cfg.cksum, err = Checksum(b); err != nil {
log.Err("conf.NewConfigFromBytes: Error calculating checksum: %s", err)
return
}
log.Debug("conf.NewConfigFromBytes: Successfully parsed and loaded configuration.")
return
}

31
conf/funcs_config.go Normal file
View File

@@ -0,0 +1,31 @@
package conf
// Checksum returns the current configuration's checksum.
func (c *Config) Checksum() (cksum []byte) {
cksum = make([]byte, len(c.cksum))
copy(cksum, c.cksum)
return
}
// IsDebug returns whether debug is enabled or not.
func (c *Config) IsDebug() (isDebug bool) {
isDebug = c.debug
return
}
/*
Path returns the config file this configuration was loaded from.
It'll be an empty string if it was loaded in directly from raw bytes.
*/
func (c *Config) Path() (path string) {
if c.confPath != nil {
path = *c.confPath
}
return
}

View File

@@ -1 +1,9 @@
package conf
// IsDebug returns whether debug is enabled or not.
func (t *Tunnel) IsDebug() (isDebug bool) {
isDebug = t.cfg.debug
return
}

View File

@@ -5,8 +5,11 @@ import (
`io/fs`
`net`
`os/user`
`text/template`
`time`
`r00t2.io/gobroke/tplCmd`
`r00t2.io/goutils/logging`
)
// Config represents a configuration file.
@@ -21,20 +24,21 @@ type Config struct {
If not (and, of course, Config.Username is specified), then Config.Username will be used for that Tunnel.
*/
Username *string `json:"default_username,omitempty" toml:"DefaultUsername,omitempty" xml:"defaultUser,attr,omitempty" yaml:"Default Username,omitempty"`
// Freq indicates the (check, not update) frequency.
Freq time.Duration `json:"freq,omitempty" toml:"Frequency,omitempty" xml:"freq,attr,omitempty" yaml:"Frequency,omitempty" default:"5m" validate:"gt=0"`
// SingleTunnel, if true, will suppress goroutine-management of tunnels and instead execute them sequentially instead.
SingleTunnel bool `json:"1tun,omitempty" toml:"SingleTunnel,omitempty" xml:"oneTun,attr,omitempty" yaml:"NoGoTunnel,omitempty"`
// CacheDB, if specified, is a path to a SQLite3 DB on-disk to make cached information persistent across reboots.
CacheDB string `json:"cache_db,omitempty" toml:"CacheDbPath,omitempty" xml:"cacheDb,attr,omitempty" yaml:"Cache Database Path,omitempty" default:":memory:" validate:"omitempty,filepath|eq=:memory:"`
// CacheDbPerms specifies the optional permissions for the file and parent directory for CacheDB; only used if persistent cache.
CacheDbPerms *Perms `json:"cache_perms,omitempty" toml:"CacheDbPerms,omitempty" xml:"cachePerms,omitempty" yaml:"Cache Database Permissions,omitempty"`
SingleTunnel bool `json:"1tun,omitempty" toml:"SingleTunnel,omitempty" xml:"oneTun,attr,omitempty" yaml:"Single Tunnel,omitempty"`
// Tunnels contains one or more tunnel configurations.
Tunnels []*Tunnel `json:"tunnels" toml:"Tunnel" xml:"tunnels>tunnel" yaml:"Tunnels" validate:"required,dive,required"`
/*
Cmds are executed, in order, *after* all Tunnel configurations have been run.
Unlike in Tunnel and ConfigTemplate, no templating on these commands is performed.
*/
Cmds []tplCmd.Cmd `json:"cmds,omitempty" toml:"Command,omitempty" xml:"commands>cmd,omitempty" yaml:"Commands,omitempty" validate:"omitempty,dive"`
Cmds []*tplCmd.Cmd `json:"cmds,omitempty" toml:"Command,omitempty" xml:"commands>cmd,omitempty" yaml:"Commands,omitempty" validate:"omitempty,dive"`
confPath *string
debug bool
log logging.Logger
cksum []byte
}
// Tunnel represents a single tunnel configuration from tunnelbroker.net.
@@ -48,7 +52,7 @@ type Tunnel struct {
*/
TunnelID uint `json:"tun_id" toml:"TunnelID" xml:"id,attr" yaml:"Tunnel ID" validate:"required,ge=1"`
/*
ExplicitAddr, if provided, will be used as the tunnelbroker.FetchedTunnel.CurrentIPv4.
ExplicitAddr, if provided, will be used as the tunnelbroker.Tunnel.ClientIPv4 for tunnelbroker.Tunnel.Update.
If not provided, this will be fetched dynamically from an external source.
*/
ExplicitAddr *net.IP `json:"addr,omitempty" toml:"ExplicitClientIP,omitempty" xml:"addr,attr,omitempty" yaml:"Explicit Client IP Address,omitempty" validate:"omitempty,ipv4"`
@@ -56,6 +60,7 @@ type Tunnel struct {
MTU should be specified if you have defined a custom one (under the "Advanced" tab for this tunnel at tunnlebroker.net).
If you did not change this, the default is 1480 (the maximum allowed), and the default value of this struct field
on configuration parsing will reflect this.
This is not used by anything directly in GoBroke, but is contained here to assist in templating that may be configured.
*/
MTU uint `json:"mtu,omitempty" toml:"MTU,omitempty" xml:"mtu,attr,omitempty" yaml:"MTU,omitempty" default:"1480" validate:"required,gt=0,le=1480"`
/*
@@ -71,15 +76,14 @@ type Tunnel struct {
*/
UpdateKey string `json:"update_key" toml:"UpdateKey" xml:"key,attr" yaml:"Update Key" validate:"required"`
// TemplateConfgs is optional. It holds templates that will be executed in order given. See ConfigTemplate.
TemplateConfigs []ConfigTemplate `json:"cfg_tpls" toml:"ConfigTemplate" xml:"config>tpl" yaml:"Configuration File Templates" validate:"omitempty,dive"`
TemplateConfigs []*ConfigTemplate `json:"cfg_tpls" toml:"ConfigTemplate" xml:"config>tpl" yaml:"Configuration File Templates" validate:"omitempty,dive"`
/*
Cmds are executed, in order, *after* all tunnel updates/fetching and the templating has completed (if any specified).
Each command will also have tunnelbroker.FetchedTunnel templated to it like TemplateConfigs/ConfigTemplate.Commands,
Each command will also have runner.TunnelResult templated to it like TemplateConfigs/ConfigTemplate.Cmds,
so they may be templated as necessary.
*/
Cmds []tplCmd.TemplateCmd `json:"cmds,omitempty" toml:"Command,omitempty" xml:"commands>cmd,omitempty" yaml:"Commands,omitempty" validate:"omitempty,dive"`
// cfg is the parent Config.
cfg *Config
Cmds []*tplCmd.TemplateCmd `json:"cmds,omitempty" toml:"Command,omitempty" xml:"commands>cmd,omitempty" yaml:"Commands,omitempty" validate:"omitempty,dive"`
cfg *Config
}
/*
@@ -95,17 +99,20 @@ type ConfigTemplate struct {
/*
Template is the path to the template file on disk.
It must follow the syntax, rules, etc. of a Golang (text/)template.Template (https://pkg.go.dev/text/template#Template).
The struct passed to it is a tunnelbroker.FetchedTunnel.
The struct passed to it is a runner.TunnelResult.
*/
Template string `json:"tpl" toml:"Template" xml:"tpl,attr" yaml:"Template File Path" validate:"required,filepath"`
// Dest contains the filepath that the Template should be written out to.
Dest string `json:"dest" toml:"Destination" xml:"dest,attr" yaml:"Destination File Path" validate:"required,filepath"`
// Perms allows specifying permissions/ownerships, if the curent user has the capability to do so.
Perms *Perms `json:"perms,omitempty" toml:"Permissions,omitempty" xml:"perms,omitempty" yaml:"Permissions and Ownership,omitempty"`
// Commands specifiies commands to run after this ConfigTemplate run.
Commands []tplCmd.TemplateCmd `json:"cmds,omitempty" toml:"Command,omitempty" xml:"cmds>cmd,omitempty" yaml:"Commands,omitempty" validate:"omitempty,dive"`
// Cmds specifiies commands to run after this ConfigTemplate run.
Cmds []*tplCmd.TemplateCmd `json:"cmds,omitempty" toml:"Command,omitempty" xml:"cmds>cmd,omitempty" yaml:"Commands,omitempty" validate:"omitempty,dive"`
// Tpl is the parsed template from Template.
Tpl *template.Template `json:"-" toml:"-" xml:"-" yaml:"-"`
}
// Perms specify permissions for a file and its parent directory.
type Perms struct {
// File specifies the desired permissions/ownership of the target file.
File *PermSpec `json:"file,omitempty" toml:"File,omitempty" xml:"file,omitempty" yaml:"File,omitempty"`
@@ -117,6 +124,7 @@ type Perms struct {
curGid int
}
// PermSpec is used to define contextual permissions. It is used for both files and their parent directories.
type PermSpec struct {
/*
User is the username or UID (tried in that order) to chown.