mirror of
https://github.com/netbirdio/netbird.git
synced 2025-08-18 11:00:06 +02:00
202 lines
5.4 KiB
Go
202 lines
5.4 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/netip"
|
|
"net/url"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/netbirdio/netbird/shared/management/domain"
|
|
mgmProto "github.com/netbirdio/netbird/shared/management/proto"
|
|
)
|
|
|
|
var (
|
|
ErrEmptyURL = errors.New("empty URL")
|
|
ErrEmptyHost = errors.New("empty host")
|
|
ErrIPNotAllowed = errors.New("IP address not allowed")
|
|
)
|
|
|
|
// ServerDomains represents the management server domains extracted from NetBird configuration
|
|
type ServerDomains struct {
|
|
Signal domain.Domain
|
|
Relay []domain.Domain
|
|
Flow domain.Domain
|
|
Stuns []domain.Domain
|
|
Turns []domain.Domain
|
|
}
|
|
|
|
// ExtractFromNetbirdConfig extracts domain information from NetBird protobuf configuration
|
|
func ExtractFromNetbirdConfig(config *mgmProto.NetbirdConfig) ServerDomains {
|
|
if config == nil {
|
|
return ServerDomains{}
|
|
}
|
|
|
|
domains := ServerDomains{}
|
|
|
|
domains.Signal = extractSignalDomain(config)
|
|
domains.Relay = extractRelayDomains(config)
|
|
domains.Flow = extractFlowDomain(config)
|
|
domains.Stuns = extractStunDomains(config)
|
|
domains.Turns = extractTurnDomains(config)
|
|
|
|
return domains
|
|
}
|
|
|
|
// ExtractValidDomain extracts a valid domain from a URL, filtering out IP addresses
|
|
func ExtractValidDomain(rawURL string) (domain.Domain, error) {
|
|
if rawURL == "" {
|
|
return "", ErrEmptyURL
|
|
}
|
|
|
|
parsedURL, err := url.Parse(rawURL)
|
|
if err == nil {
|
|
if domain, err := extractFromParsedURL(parsedURL); err != nil || domain != "" {
|
|
return domain, err
|
|
}
|
|
}
|
|
|
|
return extractFromRawString(rawURL)
|
|
}
|
|
|
|
// extractFromParsedURL handles domain extraction from successfully parsed URLs
|
|
func extractFromParsedURL(parsedURL *url.URL) (domain.Domain, error) {
|
|
if parsedURL.Hostname() != "" {
|
|
return extractDomainFromHost(parsedURL.Hostname())
|
|
}
|
|
|
|
if parsedURL.Opaque == "" || parsedURL.Scheme == "" {
|
|
return "", nil
|
|
}
|
|
|
|
// Handle URLs with opaque content (e.g., stun:host:port)
|
|
if strings.Contains(parsedURL.Scheme, ".") {
|
|
// This is likely "domain.com:port" being parsed as scheme:opaque
|
|
reconstructed := parsedURL.Scheme + ":" + parsedURL.Opaque
|
|
if host, _, err := net.SplitHostPort(reconstructed); err == nil {
|
|
return extractDomainFromHost(host)
|
|
}
|
|
return extractDomainFromHost(parsedURL.Scheme)
|
|
}
|
|
|
|
// Valid scheme with opaque content (e.g., stun:host:port)
|
|
host := parsedURL.Opaque
|
|
if queryIndex := strings.Index(host, "?"); queryIndex > 0 {
|
|
host = host[:queryIndex]
|
|
}
|
|
|
|
if hostOnly, _, err := net.SplitHostPort(host); err == nil {
|
|
return extractDomainFromHost(hostOnly)
|
|
}
|
|
|
|
return extractDomainFromHost(host)
|
|
}
|
|
|
|
// extractFromRawString handles domain extraction when URL parsing fails or returns no results
|
|
func extractFromRawString(rawURL string) (domain.Domain, error) {
|
|
if host, _, err := net.SplitHostPort(rawURL); err == nil {
|
|
return extractDomainFromHost(host)
|
|
}
|
|
|
|
return extractDomainFromHost(rawURL)
|
|
}
|
|
|
|
// extractDomainFromHost extracts domain from a host string, filtering out IP addresses
|
|
func extractDomainFromHost(host string) (domain.Domain, error) {
|
|
if host == "" {
|
|
return "", ErrEmptyHost
|
|
}
|
|
|
|
if _, err := netip.ParseAddr(host); err == nil {
|
|
return "", fmt.Errorf("%w: %s", ErrIPNotAllowed, host)
|
|
}
|
|
|
|
d, err := domain.FromString(host)
|
|
if err != nil {
|
|
return "", fmt.Errorf("invalid domain: %v", err)
|
|
}
|
|
|
|
return d, nil
|
|
}
|
|
|
|
// extractSingleDomain extracts a single domain from a URL with error logging
|
|
func extractSingleDomain(url, serviceType string) domain.Domain {
|
|
if url == "" {
|
|
return ""
|
|
}
|
|
|
|
d, err := ExtractValidDomain(url)
|
|
if err != nil {
|
|
log.Debugf("Skipping %s: %v", serviceType, err)
|
|
return ""
|
|
}
|
|
|
|
return d
|
|
}
|
|
|
|
// extractMultipleDomains extracts multiple domains from URLs with error logging
|
|
func extractMultipleDomains(urls []string, serviceType string) []domain.Domain {
|
|
var domains []domain.Domain
|
|
for _, url := range urls {
|
|
if url == "" {
|
|
continue
|
|
}
|
|
d, err := ExtractValidDomain(url)
|
|
if err != nil {
|
|
log.Debugf("Skipping %s: %v", serviceType, err)
|
|
continue
|
|
}
|
|
domains = append(domains, d)
|
|
}
|
|
return domains
|
|
}
|
|
|
|
// extractSignalDomain extracts the signal domain from NetBird configuration.
|
|
func extractSignalDomain(config *mgmProto.NetbirdConfig) domain.Domain {
|
|
if config.Signal != nil {
|
|
return extractSingleDomain(config.Signal.Uri, "signal")
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// extractRelayDomains extracts relay server domains from NetBird configuration.
|
|
func extractRelayDomains(config *mgmProto.NetbirdConfig) []domain.Domain {
|
|
if config.Relay != nil {
|
|
return extractMultipleDomains(config.Relay.Urls, "relay")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// extractFlowDomain extracts the traffic flow domain from NetBird configuration.
|
|
func extractFlowDomain(config *mgmProto.NetbirdConfig) domain.Domain {
|
|
if config.Flow != nil {
|
|
return extractSingleDomain(config.Flow.Url, "flow")
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// extractStunDomains extracts STUN server domains from NetBird configuration.
|
|
func extractStunDomains(config *mgmProto.NetbirdConfig) []domain.Domain {
|
|
var urls []string
|
|
for _, stun := range config.Stuns {
|
|
if stun != nil && stun.Uri != "" {
|
|
urls = append(urls, stun.Uri)
|
|
}
|
|
}
|
|
return extractMultipleDomains(urls, "STUN")
|
|
}
|
|
|
|
// extractTurnDomains extracts TURN server domains from NetBird configuration.
|
|
func extractTurnDomains(config *mgmProto.NetbirdConfig) []domain.Domain {
|
|
var urls []string
|
|
for _, turn := range config.Turns {
|
|
if turn != nil && turn.HostConfig != nil && turn.HostConfig.Uri != "" {
|
|
urls = append(urls, turn.HostConfig.Uri)
|
|
}
|
|
}
|
|
return extractMultipleDomains(urls, "TURN")
|
|
}
|