147 lines
3.9 KiB
Go
147 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
defaultMainListen = "0.0.0.0:80"
|
|
defaultExtraListen = "0.0.0.0:8080"
|
|
defaultDNSTTListen = "[::]:5300"
|
|
defaultUDPGWListen = "0.0.0.0:7400"
|
|
)
|
|
|
|
func normalizeRuntimePorts(cfg *Config) []string {
|
|
var warnings []string
|
|
warn := func(format string, args ...interface{}) {
|
|
msg := fmt.Sprintf(format, args...)
|
|
warnings = append(warnings, msg)
|
|
log.Printf("config safety: %s", msg)
|
|
}
|
|
|
|
cfg.Listen = strings.TrimSpace(cfg.Listen)
|
|
if cfg.Listen == "" {
|
|
cfg.Listen = defaultMainListen
|
|
}
|
|
if err := tcpAddrAvailableForPool(cfg.Listen, publicPool); err != nil {
|
|
old := cfg.Listen
|
|
cfg.Listen = defaultMainListen
|
|
warn("main listener %s is unavailable (%v); using default %s", old, err, cfg.Listen)
|
|
if err2 := tcpAddrAvailableForPool(cfg.Listen, publicPool); err2 != nil {
|
|
warn("default main listener %s is also unavailable: %v", cfg.Listen, err2)
|
|
}
|
|
}
|
|
|
|
seen := map[string]bool{cfg.Listen: true}
|
|
extra := make([]string, 0, len(cfg.ExtraListen))
|
|
for _, addr := range cfg.ExtraListen {
|
|
addr = strings.TrimSpace(addr)
|
|
if addr == "" || seen[addr] {
|
|
continue
|
|
}
|
|
if err := tcpAddrAvailableForPool(addr, publicPool); err != nil {
|
|
warn("extra listener %s is unavailable (%v)", addr, err)
|
|
fallback := defaultExtraListen
|
|
if !seen[fallback] {
|
|
if err2 := tcpAddrAvailableForPool(fallback, publicPool); err2 == nil {
|
|
extra = append(extra, fallback)
|
|
seen[fallback] = true
|
|
warn("extra listener fell back to default %s", fallback)
|
|
} else {
|
|
warn("default extra listener %s is also unavailable: %v", fallback, err2)
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
extra = append(extra, addr)
|
|
seen[addr] = true
|
|
}
|
|
cfg.ExtraListen = extra
|
|
|
|
// DragonCore no longer uses an internal local SSH listener.
|
|
cfg.LocalSSHListen = ""
|
|
|
|
if cfg.DNSTT != nil {
|
|
cfg.DNSTT.UDPListen = strings.TrimSpace(cfg.DNSTT.UDPListen)
|
|
if cfg.DNSTT.UDPListen == "" {
|
|
cfg.DNSTT.UDPListen = defaultDNSTTListen
|
|
}
|
|
if err := udpAddrAvailableForDNSTT(cfg.DNSTT.UDPListen); err != nil {
|
|
old := cfg.DNSTT.UDPListen
|
|
cfg.DNSTT.UDPListen = defaultDNSTTListen
|
|
warn("DNSTT UDP listener %s is unavailable (%v); using default %s", old, err, cfg.DNSTT.UDPListen)
|
|
if err2 := udpAddrAvailableForDNSTT(cfg.DNSTT.UDPListen); err2 != nil {
|
|
warn("default DNSTT UDP listener %s is also unavailable: %v", cfg.DNSTT.UDPListen, err2)
|
|
}
|
|
}
|
|
}
|
|
|
|
if cfg.UDPGW != nil {
|
|
cfg.UDPGW.Listen = strings.TrimSpace(cfg.UDPGW.Listen)
|
|
if cfg.UDPGW.Listen == "" {
|
|
cfg.UDPGW.Listen = defaultUDPGWListen
|
|
}
|
|
if err := tcpAddrAvailableForUDPGW(cfg.UDPGW.Listen); err != nil {
|
|
old := cfg.UDPGW.Listen
|
|
cfg.UDPGW.Listen = defaultUDPGWListen
|
|
warn("UDPGW listener %s is unavailable (%v); using default %s", old, err, cfg.UDPGW.Listen)
|
|
if err2 := tcpAddrAvailableForUDPGW(cfg.UDPGW.Listen); err2 != nil {
|
|
warn("default UDPGW listener %s is also unavailable: %v", cfg.UDPGW.Listen, err2)
|
|
}
|
|
}
|
|
}
|
|
|
|
return warnings
|
|
}
|
|
|
|
func tcpAddrAvailableForPool(addr string, pool *listenerPool) error {
|
|
if addr == "" {
|
|
return nil
|
|
}
|
|
if pool != nil && pool.Has(addr) {
|
|
return nil
|
|
}
|
|
ln, err := net.Listen("tcp", addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return ln.Close()
|
|
}
|
|
|
|
func tcpAddrAvailableForUDPGW(addr string) error {
|
|
if addr == "" {
|
|
return nil
|
|
}
|
|
globalCfgMu.RLock()
|
|
current := globalCfg != nil && globalCfg.UDPGW != nil && globalCfg.UDPGW.Listen == addr && udpgwRunning()
|
|
globalCfgMu.RUnlock()
|
|
if current {
|
|
return nil
|
|
}
|
|
ln, err := net.Listen("tcp", addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return ln.Close()
|
|
}
|
|
|
|
func udpAddrAvailableForDNSTT(addr string) error {
|
|
if addr == "" {
|
|
return nil
|
|
}
|
|
globalCfgMu.RLock()
|
|
current := globalCfg != nil && globalCfg.DNSTT != nil && globalCfg.DNSTT.UDPListen == addr && dnsttRunning()
|
|
globalCfgMu.RUnlock()
|
|
if current {
|
|
return nil
|
|
}
|
|
pc, err := net.ListenPacket("udp", addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return pc.Close()
|
|
}
|