138 lines
3.3 KiB
Go
138 lines
3.3 KiB
Go
// 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
|
||
|
|
}
|