package config
import (
"fmt"
"log"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"git.sr.ht/~sircmpwn/getopt"
"github.com/vaughan0/go-ini"
"git.sr.ht/~sircmpwn/core-go/crypto"
)
var (
Debug bool
Addr string
InternalIPNet []net.IPNet
)
// Just loads the config files
func LoadFiles() ini.File {
var (
config ini.File
err error
)
// Only loads from one of these locations
for _, path := range []string{
"config.ini",
"../config.ini",
"/etc/sr.ht/config.ini",
"/etc/sr.ht/*.ini",
} {
matches, err_ := filepath.Glob(path)
if err_ != nil {
panic(err) // only happens on bad input
}
for _, f := range matches {
if config == nil {
config, err = ini.LoadFile(f)
} else {
err = config.LoadFile(f)
}
if err != nil {
break
} else {
log.Printf("Loaded config from %s", f)
}
}
if len(matches) > 0 {
break
}
}
if err != nil {
log.Fatalf("Failed to load config file: %v", err)
}
return config
}
// Loads the application configuration, reads options from the command line,
// and initializes some internals based on these results.
func LoadConfig(defaultAddr string) ini.File {
Addr = defaultAddr
opts, _, err := getopt.Getopts(os.Args, "b:d")
if err != nil {
panic(err)
}
for _, opt := range opts {
switch opt.Option {
case 'b':
Addr = opt.Value
case 'd':
Debug = true
}
}
config := LoadFiles()
crypto.InitCrypto(config)
nets, ok := config.Get("sr.ht", "internal-ipnet")
if !ok {
nets = "127.0.0.0/8,::1/128," + // Loopback
"10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fc00::/7," + // Private
"169.254.0.0/16,fe80::/64" // Link local
}
for _, n := range strings.Split(nets, ",") {
_, net, err := net.ParseCIDR(n)
if err != nil {
panic(fmt.Errorf("[sr.ht]internal-ipnet: %w", err))
}
InternalIPNet = append(InternalIPNet, *net)
}
return config
}
func GetOrigin(conf ini.File, svc string, external bool) string {
if external {
origin, _ := conf.Get(svc, "origin")
return origin
}
origin, ok := conf.Get(svc, "internal-origin")
if ok {
return origin
}
origin, _ = conf.Get(svc, "origin")
return origin
}
const DefaultQueueSize = 512
// Returns the configured integer value for the given section and variable name.
// If nothing is configured, the default value will be returned.
// If an invalid integer is configured, this function will panic.
func GetInt(conf ini.File, section, name string, defValue int) int {
value := defValue
if s, ok := conf.Get(section, name); ok {
var err error
if value, err = strconv.Atoi(s); err != nil {
panic(fmt.Errorf("[%s]%s: %w", section, name, err))
}
}
return value
}
// Returns true if the given IP address is part of the internal networks as
// per the configuration of [sr.ht]internal-ipnet.
func IsInternalIP(ip net.IP) bool {
for _, net := range InternalIPNet {
if net.Contains(ip) {
return true
}
}
return false
}