mirror of
https://github.com/dcarrillo/whatismyip.git
synced 2026-07-23 22:45:46 +00:00
2e32a20f60
* refactor: export Settings type, Setup returns value * refactor: resolver.Setup takes explicit Settings struct * refactor: GetHeadersWithoutTrustedHeaders takes explicit header params * refactor: server constructors take narrow config * refactor: Router struct with handler methods, remove geoSvc global * refactor: wire DI through main, remove setting.App references * refactor: remove App global, use returned Settings * refactor: update router tests for DI * chore: fix lint issues — rename ServerTimeouts to Timeouts, fix shadowed variables
178 lines
5.1 KiB
Go
178 lines
5.1 KiB
Go
package setting
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/dcarrillo/whatismyip/internal/core"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
type geodbConf struct {
|
|
City string
|
|
ASN string
|
|
}
|
|
type serverSettings struct {
|
|
ReadTimeout time.Duration
|
|
WriteTimeout time.Duration
|
|
}
|
|
|
|
type resolver struct {
|
|
Domain string `yaml:"domain"`
|
|
ResourceRecords []string `yaml:"resource_records"`
|
|
RedirectPort string `yaml:"redirect_port,omitempty"`
|
|
Ipv4 []string `yaml:"ipv4,omitempty"`
|
|
Ipv6 []string `yaml:"ipv6,omitempty"`
|
|
}
|
|
|
|
type Settings struct {
|
|
GeodbPath geodbConf
|
|
TemplatePath string
|
|
BindAddress string
|
|
TLSAddress string
|
|
TLSCrtPath string
|
|
TLSKeyPath string
|
|
PrometheusAddress string
|
|
TrustedHeader string
|
|
TrustedPortHeader string
|
|
EnableSecureHeaders bool
|
|
EnableHTTP3 bool
|
|
DisableTCPScan bool
|
|
Server serverSettings
|
|
Resolver resolver
|
|
version bool
|
|
}
|
|
|
|
const defaultAddress = ":8080"
|
|
|
|
var ErrVersion = errors.New("setting: version requested")
|
|
|
|
func Setup(args []string) (cfg Settings, output string, err error) {
|
|
flags := flag.NewFlagSet("whatismyip", flag.ContinueOnError)
|
|
var buf bytes.Buffer
|
|
var resolverConf string
|
|
flags.SetOutput(&buf)
|
|
|
|
cfg.Server = serverSettings{
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
}
|
|
|
|
flags.StringVar(&cfg.GeodbPath.City, "geoip2-city", "", "Path to GeoIP2 city database. Enables geo information (--geoip2-asn becomes mandatory)")
|
|
flags.StringVar(&cfg.GeodbPath.ASN, "geoip2-asn", "", "Path to GeoIP2 ASN database. Enables ASN information. (--geoip2-city becomes mandatory)")
|
|
flags.StringVar(&cfg.TemplatePath, "template", "", "Path to the template file")
|
|
flags.StringVar(
|
|
&resolverConf,
|
|
"resolver",
|
|
"",
|
|
"Path to the resolver configuration. It actually enables the resolver for DNS client discovery.")
|
|
flags.StringVar(
|
|
&cfg.BindAddress,
|
|
"bind",
|
|
defaultAddress,
|
|
"Listening address (see https://pkg.go.dev/net?#Listen)",
|
|
)
|
|
flags.StringVar(
|
|
&cfg.TLSAddress,
|
|
"tls-bind",
|
|
"",
|
|
"Listening address for TLS (see https://pkg.go.dev/net?#Listen)",
|
|
)
|
|
flags.StringVar(&cfg.TLSCrtPath, "tls-crt", "", "When using TLS, path to certificate file")
|
|
flags.StringVar(&cfg.TLSKeyPath, "tls-key", "", "When using TLS, path to private key file")
|
|
flags.StringVar(
|
|
&cfg.PrometheusAddress,
|
|
"metrics-bind",
|
|
"",
|
|
"Listening address for Prometheus metrics endpoint (see https://pkg.go.dev/net?#Listen). It enables the metrics available at the given address/port via the /metrics endpoint.",
|
|
)
|
|
flags.StringVar(
|
|
&cfg.TrustedHeader,
|
|
"trusted-header",
|
|
"",
|
|
"Trusted request header for remote IP (e.g. X-Real-IP). When using this feature if -trusted-port-header is not set the client port is shown as 'unknown'",
|
|
)
|
|
flags.StringVar(
|
|
&cfg.TrustedPortHeader,
|
|
"trusted-port-header",
|
|
"",
|
|
"Trusted request header for remote client port (e.g. X-Real-Port). When this parameter is set -trusted-header becomes mandatory",
|
|
)
|
|
flags.BoolVar(&cfg.version, "version", false, "Output version information and exit")
|
|
flags.BoolVar(
|
|
&cfg.EnableSecureHeaders,
|
|
"enable-secure-headers",
|
|
false,
|
|
"Add sane security-related headers to every response",
|
|
)
|
|
flags.BoolVar(
|
|
&cfg.EnableHTTP3,
|
|
"enable-http3",
|
|
false,
|
|
"Enable HTTP/3 protocol. HTTP/3 requires --tls-bind set, as HTTP/3 starts as a TLS connection that then gets upgraded to UDP. The UDP port is the same as the one used for the TLS server.",
|
|
)
|
|
flags.BoolVar(
|
|
&cfg.DisableTCPScan,
|
|
"disable-scan",
|
|
false,
|
|
"Disable TCP port scanning functionality",
|
|
)
|
|
|
|
err = flags.Parse(args)
|
|
if err != nil {
|
|
return cfg, buf.String(), err
|
|
}
|
|
|
|
if cfg.version {
|
|
return cfg, fmt.Sprintf("whatismyip version %s", core.Version), ErrVersion
|
|
}
|
|
|
|
if (cfg.GeodbPath.City != "" && cfg.GeodbPath.ASN == "") || (cfg.GeodbPath.City == "" && cfg.GeodbPath.ASN != "") {
|
|
return cfg, "", errors.New("both --geoip2-city and --geoip2-asn are mandatory to enable geo information")
|
|
}
|
|
|
|
if cfg.TrustedPortHeader != "" && cfg.TrustedHeader == "" {
|
|
return cfg, "", errors.New("trusted-header is mandatory when trusted-port-header is set")
|
|
}
|
|
|
|
if (cfg.TLSAddress != "") && (cfg.TLSCrtPath == "" || cfg.TLSKeyPath == "") {
|
|
return cfg, "", errors.New("in order to use TLS, the -tls-crt and -tls-key flags are mandatory")
|
|
}
|
|
|
|
if cfg.EnableHTTP3 && cfg.TLSAddress == "" {
|
|
return cfg, "", errors.New("in order to use HTTP3, the -tls-bind is mandatory")
|
|
}
|
|
|
|
if cfg.TemplatePath != "" {
|
|
info, err := os.Stat(cfg.TemplatePath)
|
|
if err != nil {
|
|
return cfg, "", fmt.Errorf("template path: %w", err)
|
|
}
|
|
if info.IsDir() {
|
|
return cfg, "", fmt.Errorf("%s must be a file", cfg.TemplatePath)
|
|
}
|
|
}
|
|
|
|
if resolverConf != "" {
|
|
var err error
|
|
cfg.Resolver, err = readYAML(resolverConf)
|
|
if err != nil {
|
|
return cfg, "", fmt.Errorf("reading resolver configuration: %w", err)
|
|
}
|
|
}
|
|
|
|
return cfg, buf.String(), nil
|
|
}
|
|
|
|
func readYAML(path string) (resolver resolver, err error) {
|
|
yamlFile, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return resolver, err
|
|
}
|
|
return resolver, yaml.Unmarshal(yamlFile, &resolver)
|
|
}
|