update... work pending
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
152
conf/funcs.go
152
conf/funcs.go
@@ -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
31
conf/funcs_config.go
Normal 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
|
||||
}
|
||||
@@ -1 +1,9 @@
|
||||
package conf
|
||||
|
||||
// IsDebug returns whether debug is enabled or not.
|
||||
func (t *Tunnel) IsDebug() (isDebug bool) {
|
||||
|
||||
isDebug = t.cfg.debug
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user