platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
146
selective-vpn-api/app/egress_identity_probe_netns.go
Normal file
146
selective-vpn-api/app/egress_identity_probe_netns.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
egressutilpkg "selective-vpn-api/app/egressutil"
|
||||
)
|
||||
|
||||
func egressProbeExternalIPInNetns(client TransportClient, ns string) (string, error) {
|
||||
endpoints := egressLimitEndpointsForNetns(egressIPEndpoints())
|
||||
ip, errs := egressutilpkg.ProbeFirstSuccess(endpoints, func(rawURL string) (string, error) {
|
||||
return egressProbeURLInNetns(client, ns, rawURL, egressIdentityProbeTimeout)
|
||||
})
|
||||
if strings.TrimSpace(ip) != "" {
|
||||
return ip, nil
|
||||
}
|
||||
if len(errs) == 0 {
|
||||
return "", fmt.Errorf("egress probe endpoints are not configured")
|
||||
}
|
||||
return "", fmt.Errorf("%s", egressJoinErrorsCompact(errs))
|
||||
}
|
||||
|
||||
func egressProbeExternalIPInNetnsViaProxy(client TransportClient, ns, proxyURL string) (string, error) {
|
||||
proxy := strings.TrimSpace(proxyURL)
|
||||
if proxy == "" {
|
||||
return "", fmt.Errorf("proxy url is empty")
|
||||
}
|
||||
endpoints := egressLimitEndpointsForNetns(egressIPEndpoints())
|
||||
ip, errs := egressutilpkg.ProbeFirstSuccess(endpoints, func(rawURL string) (string, error) {
|
||||
return egressProbeURLInNetnsViaProxy(client, ns, rawURL, proxy, egressIdentityProbeTimeout)
|
||||
})
|
||||
if strings.TrimSpace(ip) != "" {
|
||||
return ip, nil
|
||||
}
|
||||
if len(errs) == 0 {
|
||||
return "", fmt.Errorf("egress probe endpoints are not configured")
|
||||
}
|
||||
return "", fmt.Errorf("%s", egressJoinErrorsCompact(errs))
|
||||
}
|
||||
|
||||
func egressProbeURLViaInterface(rawURL, iface string, timeout time.Duration) (string, error) {
|
||||
curl := egressutilpkg.ResolveCurlPath()
|
||||
sec := egressutilpkg.TimeoutSec(timeout)
|
||||
if curl != "" {
|
||||
args := []string{
|
||||
"-4",
|
||||
"-fsSL",
|
||||
"--max-time", strconv.Itoa(sec),
|
||||
"--connect-timeout", "2",
|
||||
"--interface", iface,
|
||||
rawURL,
|
||||
}
|
||||
stdout, stderr, code, err := runCommandTimeout(timeout+time.Second, curl, args...)
|
||||
if err != nil || code != 0 {
|
||||
return "", transportCommandError(shellJoinArgs(append([]string{curl}, args...)), stdout, stderr, code, err)
|
||||
}
|
||||
return egressutilpkg.ParseIPFromBody(stdout)
|
||||
}
|
||||
|
||||
wget := egressutilpkg.ResolveWgetPath()
|
||||
if wget == "" {
|
||||
return "", fmt.Errorf("curl/wget are not available for interface-bound egress probe")
|
||||
}
|
||||
bindAddr := egressInterfaceBindAddress(iface)
|
||||
if bindAddr == "" {
|
||||
return "", fmt.Errorf("cannot resolve IPv4 address for interface %q", iface)
|
||||
}
|
||||
args := []string{
|
||||
"-4",
|
||||
"-q",
|
||||
"-T", strconv.Itoa(sec),
|
||||
"-O", "-",
|
||||
"--bind-address", bindAddr,
|
||||
rawURL,
|
||||
}
|
||||
stdout, stderr, code, err := runCommandTimeout(timeout+time.Second, wget, args...)
|
||||
if err != nil || code != 0 {
|
||||
return "", transportCommandError(shellJoinArgs(append([]string{wget}, args...)), stdout, stderr, code, err)
|
||||
}
|
||||
return egressutilpkg.ParseIPFromBody(stdout)
|
||||
}
|
||||
|
||||
func egressProbeURLInNetns(client TransportClient, ns, rawURL string, timeout time.Duration) (string, error) {
|
||||
sec := egressutilpkg.TimeoutSec(timeout)
|
||||
resolveHost, resolvePort, resolveIP := egressutilpkg.ResolvedHostForURL(rawURL)
|
||||
|
||||
curlBin := egressutilpkg.ResolveCurlPath()
|
||||
if curlBin == "" {
|
||||
return "", fmt.Errorf("curl is not available for netns probe")
|
||||
}
|
||||
curlArgs := []string{
|
||||
"-4",
|
||||
"-fsSL",
|
||||
"--max-time", strconv.Itoa(sec),
|
||||
"--connect-timeout", "2",
|
||||
}
|
||||
if resolveHost != "" && resolveIP != "" && resolvePort > 0 {
|
||||
curlArgs = append(curlArgs, "--resolve", fmt.Sprintf("%s:%d:%s", resolveHost, resolvePort, resolveIP))
|
||||
}
|
||||
curlArgs = append(curlArgs, rawURL)
|
||||
curlCmd := append([]string{curlBin}, curlArgs...)
|
||||
name, args, err := transportNetnsExecCommand(client, ns, curlCmd...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
stdout, stderr, code, runErr := runCommandTimeout(timeout+time.Second, name, args...)
|
||||
if runErr != nil || code != 0 {
|
||||
return "", transportCommandError(shellJoinArgs(append([]string{name}, args...)), stdout, stderr, code, runErr)
|
||||
}
|
||||
return egressutilpkg.ParseIPFromBody(stdout)
|
||||
}
|
||||
|
||||
func egressProbeURLInNetnsViaProxy(
|
||||
client TransportClient,
|
||||
ns string,
|
||||
rawURL string,
|
||||
proxyURL string,
|
||||
timeout time.Duration,
|
||||
) (string, error) {
|
||||
curlBin := egressutilpkg.ResolveCurlPath()
|
||||
if curlBin == "" {
|
||||
return "", fmt.Errorf("curl is not available for proxy probe")
|
||||
}
|
||||
sec := egressutilpkg.TimeoutSec(timeout)
|
||||
args := []string{
|
||||
"-4",
|
||||
"-fsSL",
|
||||
"--max-time", strconv.Itoa(sec),
|
||||
"--connect-timeout", "3",
|
||||
"--proxy", strings.TrimSpace(proxyURL),
|
||||
rawURL,
|
||||
}
|
||||
cmd := append([]string{curlBin}, args...)
|
||||
name, netnsArgs, err := transportNetnsExecCommand(client, ns, cmd...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
stdout, stderr, code, runErr := runCommandTimeout(timeout+time.Second, name, netnsArgs...)
|
||||
if runErr != nil || code != 0 {
|
||||
return "", transportCommandError(shellJoinArgs(append([]string{name}, netnsArgs...)), stdout, stderr, code, runErr)
|
||||
}
|
||||
return egressutilpkg.ParseIPFromBody(stdout)
|
||||
}
|
||||
Reference in New Issue
Block a user