platform: modularize api/gui, add docs-tests-web foundation, and refresh root config

This commit is contained in:
beckline
2026-03-26 22:40:54 +03:00
parent 0e2d7f61ea
commit 6a56d734c2
562 changed files with 70151 additions and 16423 deletions

View 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)
}