The direct tunnel port (8446 by default) and the host agents dial for it can be set in Settings. The server moves its listeners at once and agents pick the address up from the panel: on connect and with every poll, unless TUNNEL_ADDR / TUNNEL_PORT pin it locally. ufw: run with a C locale (the output is translated), do not adopt rules that existed before the panel, skip loopback-only listeners, re-open what saved forwards need on start and when the integration is turned on, move the shared tunnel rule with the port and drop it when no direct forward is left. The last ufw error is shown in Settings. The forwards page shows the real tunnel and panel ports.
141 lines
3.4 KiB
Go
141 lines
3.4 KiB
Go
package server
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"strconv"
|
|
|
|
lpra "github.com/x-grk/longpolling-remote-access"
|
|
)
|
|
|
|
// Config keys stored in the config table.
|
|
const (
|
|
cfgHostAddress = "host_address"
|
|
cfgEnrollSecret = "enroll_secret"
|
|
cfgSetupDone = "setup_done"
|
|
cfgInstallCode = "install_code"
|
|
cfgUfwEnabled = "ufw_enabled"
|
|
cfgTunnelHost = "tunnel_host"
|
|
cfgTunnelPort = "tunnel_port"
|
|
)
|
|
|
|
// DefaultHostAddress is the public URL agents dial by default. It is baked into
|
|
// the rendered install.sh and can be changed from the settings page.
|
|
const DefaultHostAddress = "https://REDACTED:8445"
|
|
|
|
// Version is the server build version (see VERSION.txt). It is the newest
|
|
// version agents update to.
|
|
var Version = lpra.Version
|
|
|
|
// ensureDefaults seeds the host address and a random enroll secret on first boot.
|
|
func (db *DB) ensureDefaults() error {
|
|
host, err := db.GetConfig(cfgHostAddress)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if host == "" {
|
|
if err := db.SetConfig(cfgHostAddress, DefaultHostAddress); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
secret, err := db.GetConfig(cfgEnrollSecret)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if secret == "" {
|
|
if err := db.SetConfig(cfgEnrollSecret, randToken()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
code, err := db.GetConfig(cfgInstallCode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if code == "" {
|
|
if err := db.SetConfig(cfgInstallCode, shortCode()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (db *DB) HostAddress() string {
|
|
v, _ := db.GetConfig(cfgHostAddress)
|
|
if v == "" {
|
|
return DefaultHostAddress
|
|
}
|
|
return v
|
|
}
|
|
|
|
func (db *DB) EnrollSecret() string {
|
|
v, _ := db.GetConfig(cfgEnrollSecret)
|
|
return v
|
|
}
|
|
|
|
// InstallCode returns the short code used for the /i/<code> install one-liner.
|
|
func (db *DB) InstallCode() string {
|
|
v, _ := db.GetConfig(cfgInstallCode)
|
|
return v
|
|
}
|
|
|
|
// UfwEnabled reports whether panel-driven ufw integration is on (default yes).
|
|
func (db *DB) UfwEnabled() bool {
|
|
v, _ := db.GetConfig(cfgUfwEnabled)
|
|
return v != "0"
|
|
}
|
|
|
|
func (db *DB) SetUfwEnabled(on bool) error {
|
|
if on {
|
|
return db.SetConfig(cfgUfwEnabled, "1")
|
|
}
|
|
return db.SetConfig(cfgUfwEnabled, "0")
|
|
}
|
|
|
|
// TunnelHost is the host agents dial for the direct tunnel. Empty means the
|
|
// host of the URL they already reach the panel on.
|
|
func (db *DB) TunnelHost() string {
|
|
v, _ := db.GetConfig(cfgTunnelHost)
|
|
return v
|
|
}
|
|
|
|
// TunnelPort is the direct-tunnel port set in Settings, or 0 when it is left
|
|
// at the port of the server's -tunnel address.
|
|
func (db *DB) TunnelPort() int {
|
|
v, _ := db.GetConfig(cfgTunnelPort)
|
|
n, _ := strconv.Atoi(v)
|
|
if n < 1 || n > 65535 {
|
|
return 0
|
|
}
|
|
return n
|
|
}
|
|
|
|
func (db *DB) SetupDone() bool {
|
|
v, _ := db.GetConfig(cfgSetupDone)
|
|
return v == "1"
|
|
}
|
|
|
|
func (db *DB) MarkSetupDone() error { return db.SetConfig(cfgSetupDone, "1") }
|
|
|
|
// randToken returns 32 bytes of cryptographic randomness as hex (64 chars).
|
|
func randToken() string {
|
|
b := make([]byte, 32)
|
|
if _, err := rand.Read(b); err != nil {
|
|
panic("crypto/rand failed: " + err.Error())
|
|
}
|
|
return hex.EncodeToString(b)
|
|
}
|
|
|
|
// shortCode returns a short, URL-safe, typo-resistant code for install links.
|
|
// It avoids ambiguous characters (0/O, 1/l/I) so it is easy to read and type.
|
|
func shortCode() string {
|
|
const alphabet = "abcdefghjkmnpqrstuvwxyz23456789"
|
|
b := make([]byte, 7)
|
|
if _, err := rand.Read(b); err != nil {
|
|
panic("crypto/rand failed: " + err.Error())
|
|
}
|
|
for i := range b {
|
|
b[i] = alphabet[int(b[i])%len(alphabet)]
|
|
}
|
|
return string(b)
|
|
}
|