package app import ( "strings" "time" ) func transportBootstrapReplaceClientRoutes(clientID string, next []string, route transportMainRoute) error { id := sanitizeID(clientID) if id == "" { return nil } st := loadTransportBootstrapState() prev := append([]string(nil), st.Clients[id]...) next = normalizeBootstrapIPv4List(next) nextSet := map[string]struct{}{} for _, ip := range next { nextSet[ip] = struct{}{} } for _, ip := range prev { if _, keep := nextSet[ip]; keep { continue } if err := transportDeleteBootstrapRoute(ip); err != nil { return err } } for _, ip := range next { if err := transportReplaceBootstrapRoute(ip, route); err != nil { return err } } if len(st.Clients) == 0 { st.Clients = map[string][]string{} } if len(next) == 0 { delete(st.Clients, id) } else { st.Clients[id] = append([]string(nil), next...) } return saveTransportBootstrapState(st) } func transportBootstrapRemoveClientRoutes(clientID string) error { id := sanitizeID(clientID) if id == "" { return nil } st := loadTransportBootstrapState() prev := append([]string(nil), st.Clients[id]...) if len(prev) == 0 { return nil } for _, ip := range prev { if err := transportDeleteBootstrapRoute(ip); err != nil { return err } } delete(st.Clients, id) return saveTransportBootstrapState(st) } func transportReplaceBootstrapRoute(ip string, route transportMainRoute) error { args := []string{"-4", "route", "replace", ip + "/32", "table", routesTableName()} if strings.TrimSpace(route.Via) != "" { args = append(args, "via", route.Via) } args = append(args, "dev", route.Dev) stdout, stderr, code, err := transportRunCommand(5*time.Second, "ip", args...) if err != nil || code != 0 { return transportCommandError("ip "+strings.Join(args, " "), stdout, stderr, code, err) } return nil } func transportDeleteBootstrapRoute(ip string) error { args := []string{"-4", "route", "del", ip + "/32", "table", routesTableName()} stdout, stderr, code, err := transportRunCommand(5*time.Second, "ip", args...) if err == nil && code == 0 { return nil } combined := strings.ToLower(strings.TrimSpace(stderr + " " + stdout)) if strings.Contains(combined, "no such process") || strings.Contains(combined, "cannot find") { return nil } return transportCommandError("ip "+strings.Join(args, " "), stdout, stderr, code, err) }