platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
137
selective-vpn-api/app/transport_bootstrap_bypass_resolve.go
Normal file
137
selective-vpn-api/app/transport_bootstrap_bypass_resolve.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func transportResolveBootstrapIPv4(candidates []string) ([]string, error) {
|
||||
set := map[string]struct{}{}
|
||||
var warns []string
|
||||
|
||||
for _, raw := range candidates {
|
||||
host := transportNormalizeBootstrapTarget(raw)
|
||||
if host == "" {
|
||||
continue
|
||||
}
|
||||
if addr, err := netip.ParseAddr(host); err == nil {
|
||||
if addr.Is4() {
|
||||
set[addr.String()] = struct{}{}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2500*time.Millisecond)
|
||||
ipAddrs, err := net.DefaultResolver.LookupIPAddr(ctx, host)
|
||||
cancel()
|
||||
if err != nil {
|
||||
warns = append(warns, host+": "+strings.TrimSpace(err.Error()))
|
||||
continue
|
||||
}
|
||||
resolved := 0
|
||||
for _, ipa := range ipAddrs {
|
||||
v4 := ipa.IP.To4()
|
||||
if v4 == nil {
|
||||
continue
|
||||
}
|
||||
set[v4.String()] = struct{}{}
|
||||
resolved++
|
||||
}
|
||||
if resolved == 0 {
|
||||
warns = append(warns, host+": no IPv4 records")
|
||||
}
|
||||
}
|
||||
|
||||
ips := make([]string, 0, len(set))
|
||||
for ip := range set {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
sort.Strings(ips)
|
||||
|
||||
if len(warns) == 0 {
|
||||
return ips, nil
|
||||
}
|
||||
if len(warns) > 3 {
|
||||
warns = append(warns[:3], fmt.Sprintf("... and %d more", len(warns)-3))
|
||||
}
|
||||
return ips, fmt.Errorf("bootstrap resolve warnings: %s", strings.Join(warns, "; "))
|
||||
}
|
||||
|
||||
func transportNormalizeBootstrapTarget(raw string) string {
|
||||
s := strings.TrimSpace(raw)
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
if strings.Contains(s, "://") {
|
||||
if u, err := url.Parse(s); err == nil {
|
||||
host := strings.TrimSpace(u.Host)
|
||||
if host != "" {
|
||||
s = host
|
||||
} else if strings.TrimSpace(u.Opaque) != "" {
|
||||
s = strings.TrimSpace(u.Opaque)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if at := strings.LastIndex(s, "@"); at >= 0 {
|
||||
s = s[at+1:]
|
||||
}
|
||||
if idx := strings.IndexAny(s, "/?#"); idx >= 0 {
|
||||
s = s[:idx]
|
||||
}
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
if host, _, err := net.SplitHostPort(s); err == nil {
|
||||
s = host
|
||||
} else if strings.Count(s, ":") == 1 {
|
||||
i := strings.LastIndex(s, ":")
|
||||
if i > 0 {
|
||||
if _, err := strconv.Atoi(strings.TrimSpace(s[i+1:])); err == nil {
|
||||
s = s[:i]
|
||||
}
|
||||
}
|
||||
}
|
||||
s = strings.TrimSpace(strings.Trim(s, "[]"))
|
||||
s = strings.TrimSuffix(s, ".")
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
return strings.ToLower(s)
|
||||
}
|
||||
|
||||
func transportDetectMainIPv4Route() (transportMainRoute, error) {
|
||||
stdout, stderr, code, err := transportRunCommand(5*time.Second, "ip", "-4", "route", "show", "table", "main", "default")
|
||||
if err != nil || code != 0 {
|
||||
return transportMainRoute{}, transportCommandError("ip -4 route show table main default", stdout, stderr, code, err)
|
||||
}
|
||||
for _, line := range strings.Split(stdout, "\n") {
|
||||
fields := strings.Fields(strings.TrimSpace(line))
|
||||
if len(fields) == 0 || fields[0] != "default" {
|
||||
continue
|
||||
}
|
||||
route := transportMainRoute{}
|
||||
for i := 0; i < len(fields)-1; i++ {
|
||||
switch fields[i] {
|
||||
case "dev":
|
||||
route.Dev = strings.TrimSpace(fields[i+1])
|
||||
case "via":
|
||||
route.Via = strings.TrimSpace(fields[i+1])
|
||||
}
|
||||
}
|
||||
if route.Dev != "" {
|
||||
return route, nil
|
||||
}
|
||||
}
|
||||
return transportMainRoute{}, fmt.Errorf("main default route not found")
|
||||
}
|
||||
Reference in New Issue
Block a user