fea: control snat by cmd.
Some checks are pending
Coverage CI / build (push) Waiting to run
CodeQL / Analyze (go) (push) Waiting to run
Ubuntu CI / build (push) Waiting to run

This commit is contained in:
Daniel Ding
2024-10-22 10:48:33 +08:00
parent 49ecf383f4
commit a1fd32cb0b
13 changed files with 134 additions and 22 deletions

View File

@@ -162,6 +162,58 @@ func (u Network) Commands(app *api.App) {
Route{}.Commands(), Route{}.Commands(),
Link{}.Commands(), Link{}.Commands(),
FindHop{}.Commands(), FindHop{}.Commands(),
SNAT{}.Commands(),
}, },
}) })
} }
type SNAT struct {
Cmd
}
func (s SNAT) Url(prefix, name string) string {
return prefix + "/api/network/" + name + "/snat"
}
func (s SNAT) Enable(c *cli.Context) error {
network := c.String("name")
url := s.Url(c.String("url"), network)
clt := s.NewHttp(c.String("token"))
if err := clt.PostJSON(url, nil, nil); err != nil {
return err
}
return nil
}
func (s SNAT) Disable(c *cli.Context) error {
network := c.String("name")
url := s.Url(c.String("url"), network)
clt := s.NewHttp(c.String("token"))
if err := clt.DeleteJSON(url, nil, nil); err != nil {
return err
}
return nil
}
func (s SNAT) Commands() *cli.Command {
return &cli.Command{
Name: "snat",
Usage: "Control SNAT",
Subcommands: []*cli.Command{
{
Name: "enable",
Usage: "enable snat",
Action: s.Enable,
},
{
Name: "disable",
Usage: "disable snat",
Action: s.Disable,
},
},
}
}

View File

@@ -63,9 +63,9 @@ func (r Route) Save(c *cli.Context) error {
func (r Route) Tmpl() string { func (r Route) Tmpl() string {
return `# total {{ len . }} return `# total {{ len . }}
{{ps -25 "prefix"}} {{ps -25 "nexthop"}} {{ps -8 "metric"}} {{ps -8 "mode"}} {{ps -25 "prefix"}} {{ps -25 "nexthop"}} {{ps -8 "metric"}}
{{- range . }} {{- range . }}
{{ps -25 .Prefix}} {{ if .FindHop }}{{ps -25 .FindHop}}{{ else }}{{ps -25 .NextHop}}{{ end }} {{pi -8 .Metric }} {{ps -8 .Mode}} {{ps -25 .Prefix}} {{ if .FindHop }}{{ps -25 .FindHop}}{{ else }}{{ps -25 .NextHop}}{{ end }} {{pi -8 .Metric }}
{{- end }} {{- end }}
` `
} }
@@ -93,7 +93,6 @@ func (r Route) Commands() *cli.Command {
&cli.StringFlag{Name: "nexthop"}, &cli.StringFlag{Name: "nexthop"},
&cli.StringFlag{Name: "findhop"}, &cli.StringFlag{Name: "findhop"},
&cli.IntFlag{Name: "metric"}, &cli.IntFlag{Name: "metric"},
&cli.StringFlag{Name: "mode"},
}, },
Action: r.Add, Action: r.Add,
}, },

View File

@@ -10,13 +10,13 @@ type ZTrust struct {
Cmd Cmd
} }
func (z ZTrust) Url(prefix, network, action string) string { func (z ZTrust) Url(prefix, network string) string {
return prefix + "/api/network/" + network + "/ztrust/" + action return prefix + "/api/network/" + network + "/ztrust"
} }
func (z ZTrust) Enable(c *cli.Context) error { func (z ZTrust) Enable(c *cli.Context) error {
name := c.String("network") name := c.String("network")
url := z.Url(c.String("url"), name, "enable") url := z.Url(c.String("url"), name)
clt := z.NewHttp(c.String("token")) clt := z.NewHttp(c.String("token"))
if err := clt.PostJSON(url, nil, nil); err != nil { if err := clt.PostJSON(url, nil, nil); err != nil {
return err return err
@@ -26,9 +26,9 @@ func (z ZTrust) Enable(c *cli.Context) error {
func (z ZTrust) Disable(c *cli.Context) error { func (z ZTrust) Disable(c *cli.Context) error {
name := c.String("network") name := c.String("network")
url := z.Url(c.String("url"), name, "disable") url := z.Url(c.String("url"), name)
clt := z.NewHttp(c.String("token")) clt := z.NewHttp(c.String("token"))
if err := clt.PostJSON(url, nil, nil); err != nil { if err := clt.DeleteJSON(url, nil, nil); err != nil {
return err return err
} }
return nil return nil

View File

@@ -122,3 +122,40 @@ func (h Network) RestartVPN(w http.ResponseWriter, r *http.Request) {
ResponseJson(w, true) ResponseJson(w, true)
} }
type SNAT struct {
Switcher Switcher
}
func (h SNAT) Router(router *mux.Router) {
router.HandleFunc("/api/network/{id}/snat", h.Post).Methods("POST")
router.HandleFunc("/api/network/{id}/snat", h.Delete).Methods("DELETE")
}
func (h SNAT) Post(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["id"]
if obj := Call.GetWorker(name); obj != nil {
obj.DoSnat()
} else {
http.Error(w, name+" not found", http.StatusBadRequest)
return
}
ResponseJson(w, "success")
}
func (h SNAT) Delete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["id"]
if obj := Call.GetWorker(name); obj != nil {
obj.UndoSnat()
} else {
http.Error(w, name+" not found", http.StatusBadRequest)
return
}
ResponseJson(w, "success")
}

View File

@@ -26,4 +26,5 @@ func Add(router *mux.Router, switcher Switcher) {
IPSec{}.Router(router) IPSec{}.Router(router)
FindHop{}.Router(router) FindHop{}.Router(router)
Rate{Switcher: switcher}.Router(router) Rate{Switcher: switcher}.Router(router)
SNAT{}.Router(router)
} }

View File

@@ -32,7 +32,7 @@ func ResponseMsg(w http.ResponseWriter, code int, message string) {
func ResponseYaml(w http.ResponseWriter, v interface{}) { func ResponseYaml(w http.ResponseWriter, v interface{}) {
str, err := yaml.Marshal(v) str, err := yaml.Marshal(v)
if err == nil { if err == nil {
w.Header().Set("Content-Type", "application/yaml") w.Header().Set("Content-Type", "text/plain")
_, _ = w.Write(str) _, _ = w.Write(str)
} else { } else {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)

View File

@@ -16,6 +16,8 @@ type ZTrust struct {
func (h ZTrust) Router(router *mux.Router) { func (h ZTrust) Router(router *mux.Router) {
router.HandleFunc("/api/network/{id}/ztrust", h.List).Methods("GET") router.HandleFunc("/api/network/{id}/ztrust", h.List).Methods("GET")
router.HandleFunc("/api/network/{id}/ztrust", h.Enable).Methods("POST")
router.HandleFunc("/api/network/{id}/ztrust", h.Disable).Methods("DELETE")
router.HandleFunc("/api/network/{id}/ztrust/enable", h.Enable).Methods("POST") router.HandleFunc("/api/network/{id}/ztrust/enable", h.Enable).Methods("POST")
router.HandleFunc("/api/network/{id}/ztrust/disable", h.Disable).Methods("POST") router.HandleFunc("/api/network/{id}/ztrust/disable", h.Disable).Methods("POST")
router.HandleFunc("/api/network/{id}/guest", h.ListGuest).Methods("GET") router.HandleFunc("/api/network/{id}/guest", h.ListGuest).Methods("GET")

View File

@@ -48,6 +48,9 @@ func (n *Network) Correct(sw *Switch) {
if n.Bridge == nil { if n.Bridge == nil {
n.Bridge = &Bridge{} n.Bridge = &Bridge{}
} }
if n.Snat == "" {
n.Snat = "enable"
}
switch n.Provider { switch n.Provider {
case "router": case "router":
spec := n.Specifies spec := n.Specifies
@@ -77,6 +80,7 @@ func (n *Network) Correct(sw *Switch) {
n.Subnet.Netmask = ipMask n.Subnet.Netmask = ipMask
} }
CorrectRoutes(n.Routes, ipAddr) CorrectRoutes(n.Routes, ipAddr)
if n.OpenVPN != nil { if n.OpenVPN != nil {
n.OpenVPN.Network = n.Name n.OpenVPN.Network = n.Name
obj := DefaultOpenVPN() obj := DefaultOpenVPN()

View File

@@ -29,7 +29,6 @@ type PrefixRoute struct {
NextHop string `json:"nexthop"` NextHop string `json:"nexthop"`
MultiPath []MultiPath `json:"multipath,omitempty"` MultiPath []MultiPath `json:"multipath,omitempty"`
Metric int `json:"metric"` Metric int `json:"metric"`
Mode string `json:"forward,omitempty"` // route or snat
FindHop string `json:"findhop,omitempty"` FindHop string `json:"findhop,omitempty"`
} }
@@ -44,9 +43,6 @@ func (r *PrefixRoute) String() string {
if len(r.FindHop) > 0 { if len(r.FindHop) > 0 {
elems = append(elems, fmt.Sprintf("Findhop: %s", r.FindHop)) elems = append(elems, fmt.Sprintf("Findhop: %s", r.FindHop))
} }
if len(r.Mode) > 0 {
elems = append(elems, fmt.Sprintf("Forward: %s", r.Mode))
}
if r.Metric > 0 { if r.Metric > 0 {
elems = append(elems, fmt.Sprintf("Metric: %d", r.Metric)) elems = append(elems, fmt.Sprintf("Metric: %d", r.Metric))
} }
@@ -60,9 +56,6 @@ func (r *PrefixRoute) CorrectRoute(nexthop string) {
if r.NextHop == "" { if r.NextHop == "" {
r.NextHop = nexthop r.NextHop = nexthop
} }
if r.Mode == "" {
r.Mode = "snat"
}
} }
func CorrectRoutes(routes []PrefixRoute, nexthop string) { func CorrectRoutes(routes []PrefixRoute, nexthop string) {

View File

@@ -11,7 +11,6 @@ type Route struct {
Prefix string `json:"prefix"` Prefix string `json:"prefix"`
NextHop string `json:"nexthop"` NextHop string `json:"nexthop"`
Metric int `json:"metric"` Metric int `json:"metric"`
Mode string `json:"mode"`
Origin string `json:"origin"` Origin string `json:"origin"`
MultiPath []MultiPath `json:"multipath,omitempty"` MultiPath []MultiPath `json:"multipath,omitempty"`
} }
@@ -21,12 +20,11 @@ type MultiPath struct {
Weight int `json:"weight"` Weight int `json:"weight"`
} }
func NewRoute(prefix string, nexthop, mode string) (this *Route) { func NewRoute(prefix, nexthop string) (this *Route) {
this = &Route{ this = &Route{
Prefix: prefix, Prefix: prefix,
NextHop: nexthop, NextHop: nexthop,
Metric: 250, Metric: 250,
Mode: mode,
} }
return return
} }

View File

@@ -125,6 +125,12 @@
<td>Built on:</td> <td>Built on:</td>
<td>{{ .Version.Date }}</td> <td>{{ .Version.Date }}</td>
</tr> </tr>
<tr>
<td>APIs:</td>
<td>
<a href="/api/urls">display</a>
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@@ -136,6 +136,7 @@ func (h *Http) LoadRouter() {
h.PProf(router) h.PProf(router)
h.Prome(router) h.Prome(router)
router.HandleFunc("/api/index", h.GetIndex).Methods("GET") router.HandleFunc("/api/index", h.GetIndex).Methods("GET")
router.HandleFunc("/api/urls", h.GetApi).Methods("GET")
api.Add(router, h.switcher) api.Add(router, h.switcher)
} }
@@ -353,3 +354,22 @@ func (h *Http) GetIndex(w http.ResponseWriter, r *http.Request) {
h.getIndex(&body) h.getIndex(&body)
api.ResponseJson(w, body) api.ResponseJson(w, body)
} }
func (t *Http) GetApi(w http.ResponseWriter, r *http.Request) {
var urls []string
t.router.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
path, err := route.GetPathTemplate()
if err != nil || !strings.HasPrefix(path, "/api") {
return nil
}
methods, err := route.GetMethods()
if err != nil {
return nil
}
for _, m := range methods {
urls = append(urls, fmt.Sprintf("%-6s %s", m, path))
}
return nil
})
api.ResponseYaml(w, urls)
}

View File

@@ -78,7 +78,7 @@ func (w *WorkerImpl) newRoute(rt *co.PrefixRoute) *models.Route {
w.out.Warn("WorkerImpl.NewRoute: %s noNextHop", rt.Prefix) w.out.Warn("WorkerImpl.NewRoute: %s noNextHop", rt.Prefix)
return nil return nil
} }
rte := models.NewRoute(rt.Prefix, w.IfAddr(), rt.Mode) rte := models.NewRoute(rt.Prefix, w.IfAddr())
if rt.Metric > 0 { if rt.Metric > 0 {
rte.Metric = rt.Metric rte.Metric = rt.Metric
} }
@@ -412,7 +412,7 @@ func (w *WorkerImpl) undoSnat() {
func (w *WorkerImpl) DoSnat() { func (w *WorkerImpl) DoSnat() {
cfg, _ := w.GetCfgs() cfg, _ := w.GetCfgs()
if cfg.Snat != "disable" { if cfg.Snat == "disable" {
cfg.Snat = "enable" cfg.Snat = "enable"
w.doSnat() w.doSnat()
} }
@@ -420,7 +420,7 @@ func (w *WorkerImpl) DoSnat() {
func (w *WorkerImpl) UndoSnat() { func (w *WorkerImpl) UndoSnat() {
cfg, _ := w.GetCfgs() cfg, _ := w.GetCfgs()
if cfg.Snat == "disable" { if cfg.Snat != "disable" {
cfg.Snat = "disable" cfg.Snat = "disable"
w.undoSnat() w.undoSnat()
} }