package app import ( "fmt" "strings" ) const transportBootstrapStateVersion = 1 var transportBootstrapStatePath = transportBootstrapPath type transportBootstrapState struct { Version int `json:"version"` UpdatedAt string `json:"updated_at,omitempty"` Clients map[string][]string `json:"clients,omitempty"` } type transportMainRoute struct { Dev string Via string } func transportMaybeSyncBootstrapBypass(client TransportClient, action string) (string, error) { act := strings.ToLower(strings.TrimSpace(action)) switch act { case "start", "restart", "stop": default: return "", nil } if !transportBootstrapBypassEnabled(client) { return "", nil } if act == "stop" { if err := transportBootstrapRemoveClientRoutes(client.ID); err != nil { return "", err } return "bootstrap bypass routes removed", nil } return transportBootstrapSyncClientRoutes(client) } func transportBootstrapBypassEnabled(client TransportClient) bool { if transportConfigHasKey(client.Config, "bootstrap_bypass") { return transportConfigBool(client.Config, "bootstrap_bypass") } // Default: enable for SingBox only. return client.Kind == TransportClientSingBox } func transportBootstrapBypassStrict(client TransportClient) bool { return transportConfigBool(client.Config, "bootstrap_bypass_strict") } func transportBootstrapSyncClientRoutes(client TransportClient) (string, error) { candidates := transportCollectBootstrapCandidates(client) ips, resolveWarn := transportResolveBootstrapIPv4(candidates) if len(ips) == 0 { if err := transportBootstrapReplaceClientRoutes(client.ID, nil, transportMainRoute{}); err != nil { return "", err } if resolveWarn != nil { return "", resolveWarn } return "bootstrap bypass: no endpoints found", nil } mainRoute, err := transportDetectMainIPv4Route() if err != nil { return "", err } if err := transportBootstrapReplaceClientRoutes(client.ID, ips, mainRoute); err != nil { return "", err } msg := fmt.Sprintf( "bootstrap bypass synced: ips=%d via=%s dev=%s", len(ips), transportOr(mainRoute.Via, "link"), mainRoute.Dev, ) if resolveWarn != nil { msg += "; " + resolveWarn.Error() } return msg, nil } func transportCommandError(cmd, stdout, stderr string, code int, err error) error { msg := strings.TrimSpace(stderr) if msg == "" { msg = strings.TrimSpace(stdout) } if msg == "" && err != nil { msg = strings.TrimSpace(err.Error()) } if msg == "" { msg = fmt.Sprintf("exit code %d", code) } if err != nil { return fmt.Errorf("%s failed: %s", strings.TrimSpace(cmd), msg) } return fmt.Errorf("%s failed (code=%d): %s", strings.TrimSpace(cmd), code, msg) } func transportOr(v, fallback string) string { if strings.TrimSpace(v) != "" { return strings.TrimSpace(v) } return strings.TrimSpace(fallback) }