Files

138 lines
3.3 KiB
Go
Raw Permalink Normal View History

// SPDX-License-Identifier: MIT
package cli
import (
"context"
"fmt"
"io"
"github.com/spf13/cobra"
"prx/internal/config"
"prx/internal/proto"
"prx/internal/state"
)
func (a *app) newBypassCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "bypass",
Short: "Manage destinations that must bypass the proxy",
}
cmd.AddCommand(a.newBypassAddCmd(), a.newBypassRmCmd(), a.newBypassLsCmd())
return cmd
}
func (a *app) newBypassAddCmd() *cobra.Command {
return &cobra.Command{
Use: "add <cidr|ip|domain>",
Short: "Add a CIDR/IP (routed direct) or domain (engine hint) to the bypass list",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cfg, err := a.loadConfig()
if err != nil {
return err
}
arg := args[0]
var changed bool
if config.IsCIDR(arg) {
changed, err = cfg.AddExtraCIDR(arg)
} else {
changed, err = cfg.AddDomain(arg)
}
if err != nil {
return err
}
if !changed {
fmt.Fprintln(a.out, "already present")
return nil
}
if err := config.Save(a.configPath, cfg); err != nil {
return err
}
fmt.Fprintf(a.out, "added %s to bypass list\n", arg)
return a.reapplyIfEnabled(cmd.Context(), cfg)
},
}
}
func (a *app) newBypassRmCmd() *cobra.Command {
return &cobra.Command{
Use: "rm <cidr|ip|domain>",
Short: "Remove an entry from the bypass list",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cfg, err := a.loadConfig()
if err != nil {
return err
}
arg := args[0]
var changed bool
if config.IsCIDR(arg) {
changed, err = cfg.RemoveExtraCIDR(arg)
} else {
changed = cfg.RemoveDomain(arg)
}
if err != nil {
return err
}
if !changed {
fmt.Fprintln(a.out, "not present")
return nil
}
if err := config.Save(a.configPath, cfg); err != nil {
return err
}
fmt.Fprintf(a.out, "removed %s from bypass list\n", arg)
return a.reapplyIfEnabled(cmd.Context(), cfg)
},
}
}
func (a *app) newBypassLsCmd() *cobra.Command {
return &cobra.Command{
Use: "ls",
Short: "List bypass entries",
Args: cobra.NoArgs,
RunE: func(_ *cobra.Command, _ []string) error {
cfg, err := a.loadConfig()
if err != nil {
return err
}
writeList(a.out, "always (engine hints):", cfg.Bypass.AlwaysCIDRs, false)
writeList(a.out, "extra CIDRs (routed direct):", cfg.Bypass.ExtraCIDRs, true)
writeList(a.out, "domains (engine hints):", cfg.Bypass.Domains, true)
return nil
},
}
}
// writeList prints a labelled list, showing "(none)" when empty and showEmpty.
func writeList(w io.Writer, label string, items []string, showEmpty bool) {
fmt.Fprintln(w, label)
if len(items) == 0 && showEmpty {
fmt.Fprintln(w, " (none)")
}
for _, item := range items {
fmt.Fprintln(w, " "+item)
}
}
// reapplyIfEnabled refreshes the routing rules when prx is currently enabled so
// bypass changes take effect immediately.
func (a *app) reapplyIfEnabled(ctx context.Context, cfg *config.Config) error {
st, err := state.Load(cfg.State.Path)
if err != nil {
return err
}
if !st.Enabled {
fmt.Fprintln(a.out, "takes effect on the next 'prx on'")
return nil
}
if err := a.dispatch(ctx, cfg, proto.ActionApply, nil); err != nil {
return err
}
fmt.Fprintln(a.out, "routing rules refreshed")
return nil
}