mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-19 20:09:07 +02:00
[proxy,client] Add --external-ip-map flag for the embedded client (#8185)
* [proxy] Add --external-ip-map flag for the embedded client The proxy behind a NAT with a forwarded fixed --wg-port could not advertise its public address as an ICE candidate, so peers fell back to relay. Expose the agent's external IP map through embed.Options and a proxy flag (NB_PROXY_EXTERNAL_IP_MAP). * [proxy] Validate --external-ip-map at startup The engine drops every external IP mapping when one fails to parse, so a typo or a space after a comma silently disabled the feature. Move the agent's validator to shared/externalipmap, run it from the proxy at startup, and trim entries first. * [client,proxy] Require an external IP first in --external-ip-map The engine reads the first component as the external IP, so a mapping like iface/10.0.0.5 passed validation and then dropped every mapping.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
// Package externalipmap validates the --external-ip-map flag shared by the
|
||||
// agent and the proxy.
|
||||
package externalipmap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const flagName = "external-ip-map"
|
||||
|
||||
// Validate checks each element is formatted as "IP", "IP/IP" or
|
||||
// "IP/interface". The engine drops every mapping when one element fails to
|
||||
// parse, so callers should reject bad input up front.
|
||||
func Validate(list []string) error {
|
||||
for _, element := range list {
|
||||
if element == "" {
|
||||
return fmt.Errorf("empty string is not a valid input for %s", flagName)
|
||||
}
|
||||
|
||||
subElements := strings.Split(element, "/")
|
||||
if len(subElements) > 2 {
|
||||
return fmt.Errorf("%s is not a valid input for %s. it should be formatted as \"String\" or \"String/String\"", element, flagName)
|
||||
}
|
||||
|
||||
if !isValidIP(subElements[0]) {
|
||||
return fmt.Errorf("%s is not a valid input for %s. it should be formatted as \"IP\" or \"IP/IP\", or \"IP/Interface Name\"", element, flagName)
|
||||
}
|
||||
|
||||
if len(subElements) == 2 {
|
||||
if err := validateInternal(subElements[1]); err != nil {
|
||||
return fmt.Errorf("%s is not a valid input for %s. it should be an IP string or a network name: %w", subElements[1], flagName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateInternal(element string) error {
|
||||
if isValidIP(element) {
|
||||
return nil
|
||||
}
|
||||
validIface, err := isValidInterface(element)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate network interface name: %w", err)
|
||||
}
|
||||
if !validIface {
|
||||
return fmt.Errorf("invalid IP or network interface name not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// isValidIP uses net.ParseIP to match the engine's parser exactly.
|
||||
func isValidIP(ip string) bool {
|
||||
return net.ParseIP(ip) != nil
|
||||
}
|
||||
|
||||
func isValidInterface(name string) (bool, error) {
|
||||
netInterfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, iface := range netInterfaces {
|
||||
if iface.Name == name {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
Reference in New Issue
Block a user