diff --git a/cmd/api/v5/cmd.go b/cmd/api/v5/cmd.go index 48fbede..3a0342e 100755 --- a/cmd/api/v5/cmd.go +++ b/cmd/api/v5/cmd.go @@ -42,4 +42,5 @@ func Commands(app *api.App) { Rate{}.Commands(app) Ceci{}.Commands(app) BGP{}.Commands(app) + Prefix{}.Commands(app) } diff --git a/cmd/api/v5/device.go b/cmd/api/v5/device.go deleted file mode 100755 index 7241b34..0000000 --- a/cmd/api/v5/device.go +++ /dev/null @@ -1,53 +0,0 @@ -package v5 - -import ( - "github.com/luscis/openlan/cmd/api" - "github.com/luscis/openlan/pkg/schema" - "github.com/urfave/cli/v2" -) - -type Device struct { - Cmd -} - -func (u Device) Url(prefix, name string) string { - if name == "" { - return prefix + "/api/device" - } else { - return prefix + "/api/device/" + name - } -} - -func (u Device) Tmpl() string { - return `# total {{ len . }} -{{ps -13 "name"}} {{ps -13 "mtu"}} {{ps -16 "mac"}} {{ps -6 "provider"}} -{{- range . }} -{{ps -13 .Name}} {{pi -13 .Mtu}} {{ps -16 .Mac}} {{ps -6 .Provider}} -{{- end }} -` -} - -func (u Device) List(c *cli.Context) error { - url := u.Url(c.String("url"), "") - clt := u.NewHttp(c.String("token")) - var items []schema.Device - if err := clt.GetJSON(url, &items); err != nil { - return err - } - return u.Out(items, c.String("format"), u.Tmpl()) -} - -func (u Device) Commands(app *api.App) { - app.Command(&cli.Command{ - Name: "device", - Usage: "linux network device", - Subcommands: []*cli.Command{ - { - Name: "list", - Usage: "Display all devices", - Aliases: []string{"ls"}, - Action: u.List, - }, - }, - }) -} diff --git a/cmd/api/v5/log.go b/cmd/api/v5/log.go deleted file mode 100755 index c0e63a1..0000000 --- a/cmd/api/v5/log.go +++ /dev/null @@ -1,62 +0,0 @@ -package v5 - -import ( - "github.com/luscis/openlan/cmd/api" - "github.com/luscis/openlan/pkg/schema" - "github.com/urfave/cli/v2" -) - -type Log struct { - Cmd -} - -func (v Log) Url(prefix, name string) string { - return prefix + "/api/log" -} - -func (v Log) Tmpl() string { - return `File : {{ .File }} -Level: {{ .Level}} -` -} - -func (v Log) List(c *cli.Context) error { - url := v.Url(c.String("url"), "") - clt := v.NewHttp(c.String("token")) - var item schema.Log - if err := clt.GetJSON(url, &item); err != nil { - return err - } - return v.Out(item, c.String("format"), v.Tmpl()) -} - -func (v Log) Add(c *cli.Context) error { - url := v.Url(c.String("url"), "") - log := &schema.Log{ - Level: c.Int("level"), - } - clt := v.NewHttp(c.String("token")) - if err := clt.PostJSON(url, log, nil); err != nil { - return err - } - return nil -} - -func (v Log) Commands(app *api.App) { - app.Command(&cli.Command{ - Name: "log", - Aliases: []string{"v"}, - Usage: "show log information", - Action: v.List, - Subcommands: []*cli.Command{ - { - Name: "set", - Usage: "set log level", - Flags: []cli.Flag{ - &cli.IntFlag{Name: "level"}, - }, - Action: v.Add, - }, - }, - }) -} diff --git a/cmd/api/v5/pprof.go b/cmd/api/v5/pprof.go deleted file mode 100755 index d20ec77..0000000 --- a/cmd/api/v5/pprof.go +++ /dev/null @@ -1,76 +0,0 @@ -package v5 - -import ( - "fmt" - - "github.com/luscis/openlan/cmd/api" - "github.com/luscis/openlan/pkg/libol" - "github.com/luscis/openlan/pkg/schema" - "github.com/urfave/cli/v2" -) - -type PProf struct { - Cmd -} - -func (u PProf) Url(prefix, name string) string { - return prefix + "/api/pprof" -} - -func (u PProf) Add(c *cli.Context) error { - pp := schema.PProf{ - Listen: c.String("listen"), - } - if pp.Listen == "" { - return libol.NewErr("listen value is empty") - } - url := u.Url(c.String("url"), "") - clt := u.NewHttp(c.String("token")) - if err := clt.PostJSON(url, pp, nil); err != nil { - return err - } - return nil -} - -func (u PProf) Del(c *cli.Context) error { - url := u.Url(c.String("url"), "") - clt := u.NewHttp(c.String("token")) - if err := clt.DeleteJSON(url, nil, nil); err != nil { - return err - } - return nil -} - -func (u PProf) List(c *cli.Context) error { - url := u.Url(c.String("url"), "") - clt := u.NewHttp(c.String("token")) - var pp schema.PProf - if err := clt.GetJSON(url, &pp); err != nil { - return err - } - fmt.Println(pp.Listen) - return nil -} - -func (u PProf) Commands(app *api.App) { - app.Command(&cli.Command{ - Name: "pprof", - Usage: "Debug pprof tool", - Subcommands: []*cli.Command{ - { - Name: "list", - Usage: "Show configuration", - Aliases: []string{"ls"}, - Action: u.List, - }, - { - Name: "enable", - Usage: "Enable pprof tool", - Flags: []cli.Flag{ - &cli.StringFlag{Name: "listen", Value: "127.0.0.1:6060"}, - }, - Action: u.Add, - }, - }, - }) -} diff --git a/cmd/api/v5/system.go b/cmd/api/v5/system.go new file mode 100644 index 0000000..21280b3 --- /dev/null +++ b/cmd/api/v5/system.go @@ -0,0 +1,219 @@ +package v5 + +import ( + "fmt" + + "github.com/luscis/openlan/cmd/api" + "github.com/luscis/openlan/pkg/libol" + "github.com/luscis/openlan/pkg/schema" + "github.com/urfave/cli/v2" +) + +type Prefix struct { + Cmd +} + +func (r Prefix) Url(prefix string) string { + return prefix + "/api/prefix" +} + +func (r Prefix) Tmpl() string { + return `# total {{ len . }} +{{ps -18 "destination"}} {{ps -15 "nexthop"}} {{ps -16 "link"}} {{ps -15 "source"}} {{"metric"}} +{{- range . }} +{{ps -18 .Prefix}} {{ps -15 .NextHop}} {{ps -16 .Link}} {{ps -15 .Source}} {{.Metric}} +{{- end }} +` +} + +func (r Prefix) List(c *cli.Context) error { + url := r.Url(c.String("url")) + clt := r.NewHttp(c.String("token")) + var items []schema.PrefixRoute + if err := clt.GetJSON(url, &items); err != nil { + return err + } + return r.Out(items, c.String("format"), r.Tmpl()) +} + +func (r Prefix) Commands(app *api.App) { + app.Command(&cli.Command{ + Name: "prefix", + Usage: "System prefix", + Subcommands: []*cli.Command{ + { + Name: "list", + Aliases: []string{"ls"}, + Usage: "List system routes.", + Action: r.List, + }, + }, + }) +} + +type Log struct { + Cmd +} + +func (v Log) Url(prefix, name string) string { + return prefix + "/api/log" +} + +func (v Log) Tmpl() string { + return `File : {{ .File }} +Level: {{ .Level}} +` +} + +func (v Log) List(c *cli.Context) error { + url := v.Url(c.String("url"), "") + clt := v.NewHttp(c.String("token")) + var item schema.Log + if err := clt.GetJSON(url, &item); err != nil { + return err + } + return v.Out(item, c.String("format"), v.Tmpl()) +} + +func (v Log) Add(c *cli.Context) error { + url := v.Url(c.String("url"), "") + log := &schema.Log{ + Level: c.Int("level"), + } + clt := v.NewHttp(c.String("token")) + if err := clt.PostJSON(url, log, nil); err != nil { + return err + } + return nil +} + +func (v Log) Commands(app *api.App) { + app.Command(&cli.Command{ + Name: "log", + Aliases: []string{"v"}, + Usage: "show log information", + Action: v.List, + Subcommands: []*cli.Command{ + { + Name: "set", + Usage: "set log level", + Flags: []cli.Flag{ + &cli.IntFlag{Name: "level"}, + }, + Action: v.Add, + }, + }, + }) +} + +type Device struct { + Cmd +} + +func (u Device) Url(prefix, name string) string { + if name == "" { + return prefix + "/api/device" + } else { + return prefix + "/api/device/" + name + } +} + +func (u Device) Tmpl() string { + return `# total {{ len . }} +{{ps -13 "name"}} {{ps -13 "mtu"}} {{ps -16 "mac"}} {{ps -6 "provider"}} +{{- range . }} +{{ps -13 .Name}} {{pi -13 .Mtu}} {{ps -16 .Mac}} {{ps -6 .Provider}} +{{- end }} +` +} + +func (u Device) List(c *cli.Context) error { + url := u.Url(c.String("url"), "") + clt := u.NewHttp(c.String("token")) + var items []schema.Device + if err := clt.GetJSON(url, &items); err != nil { + return err + } + return u.Out(items, c.String("format"), u.Tmpl()) +} + +func (u Device) Commands(app *api.App) { + app.Command(&cli.Command{ + Name: "device", + Usage: "linux network device", + Subcommands: []*cli.Command{ + { + Name: "list", + Usage: "Display all devices", + Aliases: []string{"ls"}, + Action: u.List, + }, + }, + }) +} + +type PProf struct { + Cmd +} + +func (u PProf) Url(prefix, name string) string { + return prefix + "/api/pprof" +} + +func (u PProf) Add(c *cli.Context) error { + pp := schema.PProf{ + Listen: c.String("listen"), + } + if pp.Listen == "" { + return libol.NewErr("listen value is empty") + } + url := u.Url(c.String("url"), "") + clt := u.NewHttp(c.String("token")) + if err := clt.PostJSON(url, pp, nil); err != nil { + return err + } + return nil +} + +func (u PProf) Del(c *cli.Context) error { + url := u.Url(c.String("url"), "") + clt := u.NewHttp(c.String("token")) + if err := clt.DeleteJSON(url, nil, nil); err != nil { + return err + } + return nil +} + +func (u PProf) List(c *cli.Context) error { + url := u.Url(c.String("url"), "") + clt := u.NewHttp(c.String("token")) + var pp schema.PProf + if err := clt.GetJSON(url, &pp); err != nil { + return err + } + fmt.Println(pp.Listen) + return nil +} + +func (u PProf) Commands(app *api.App) { + app.Command(&cli.Command{ + Name: "pprof", + Usage: "Debug pprof tool", + Subcommands: []*cli.Command{ + { + Name: "list", + Usage: "Show configuration", + Aliases: []string{"ls"}, + Action: u.List, + }, + { + Name: "enable", + Usage: "Enable pprof tool", + Flags: []cli.Flag{ + &cli.StringFlag{Name: "listen", Value: "127.0.0.1:6060"}, + }, + Action: u.Add, + }, + }, + }) +} diff --git a/pkg/api/api.go b/pkg/api/api.go index bfff528..dcd3904 100755 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -112,10 +112,10 @@ type Networker interface { Qoser() Qoser ACLer() ACLer FindHoper() FindHoper - DoZTrust() - UndoZTrust() - DoSnat() - UndoSnat() + EnableZTrust() + DisableZTrust() + EnableSnat() + DisableSnat() } type IPSecer interface { diff --git a/pkg/api/log.go b/pkg/api/log.go deleted file mode 100755 index b1f5dcb..0000000 --- a/pkg/api/log.go +++ /dev/null @@ -1,34 +0,0 @@ -package api - -import ( - "net/http" - - "github.com/gorilla/mux" - "github.com/luscis/openlan/pkg/libol" - "github.com/luscis/openlan/pkg/schema" -) - -type Log struct { -} - -func (l Log) Router(router *mux.Router) { - router.HandleFunc("/api/log", l.List).Methods("GET") - router.HandleFunc("/api/log", l.Add).Methods("POST") -} - -func (l Log) List(w http.ResponseWriter, r *http.Request) { - log := schema.NewLogSchema() - ResponseJson(w, log) -} - -func (l Log) Add(w http.ResponseWriter, r *http.Request) { - log := &schema.Log{} - if err := GetData(r, log); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - libol.SetLevel(log.Level) - - ResponseMsg(w, 0, "") -} diff --git a/pkg/api/network.go b/pkg/api/network.go index acdea05..cf720c7 100755 --- a/pkg/api/network.go +++ b/pkg/api/network.go @@ -138,7 +138,7 @@ func (h SNAT) Post(w http.ResponseWriter, r *http.Request) { name := vars["id"] if obj := Call.GetWorker(name); obj != nil { - obj.DoSnat() + obj.EnableSnat() } else { http.Error(w, name+" not found", http.StatusBadRequest) return @@ -152,7 +152,7 @@ func (h SNAT) Delete(w http.ResponseWriter, r *http.Request) { name := vars["id"] if obj := Call.GetWorker(name); obj != nil { - obj.UndoSnat() + obj.DisableSnat() } else { http.Error(w, name+" not found", http.StatusBadRequest) return diff --git a/pkg/api/device.go b/pkg/api/system.go similarity index 64% rename from pkg/api/device.go rename to pkg/api/system.go index 0d0fcb5..c034e41 100755 --- a/pkg/api/device.go +++ b/pkg/api/system.go @@ -1,14 +1,43 @@ package api import ( - "github.com/gorilla/mux" - "github.com/luscis/openlan/pkg/network" - "github.com/luscis/openlan/pkg/schema" "net" "net/http" "time" + + "github.com/gorilla/mux" + "github.com/luscis/openlan/pkg/libol" + "github.com/luscis/openlan/pkg/network" + "github.com/luscis/openlan/pkg/schema" ) +type Prefix struct { +} + +func (l Prefix) Router(router *mux.Router) { + router.HandleFunc("/api/prefix", l.List).Methods("GET") +} + +func (l Prefix) List(w http.ResponseWriter, r *http.Request) { + var items []schema.PrefixRoute + + routes, _ := libol.ListRoutes() + for _, prefix := range routes { + item := schema.PrefixRoute{ + Link: prefix.Link, + Metric: prefix.Priority, + Table: prefix.Table, + Source: prefix.Src, + NextHop: prefix.Gw, + Prefix: prefix.Dst, + } + items = append(items, item) + + } + + ResponseJson(w, items) +} + type Device struct { } @@ -89,3 +118,28 @@ func (h Device) Get(w http.ResponseWriter, r *http.Request) { http.Error(w, vars["id"], http.StatusNotFound) } } + +type Log struct { +} + +func (l Log) Router(router *mux.Router) { + router.HandleFunc("/api/log", l.List).Methods("GET") + router.HandleFunc("/api/log", l.Add).Methods("POST") +} + +func (l Log) List(w http.ResponseWriter, r *http.Request) { + log := schema.NewLogSchema() + ResponseJson(w, log) +} + +func (l Log) Add(w http.ResponseWriter, r *http.Request) { + log := &schema.Log{} + if err := GetData(r, log); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + libol.SetLevel(log.Level) + + ResponseMsg(w, 0, "") +} diff --git a/pkg/api/url.go b/pkg/api/url.go index c287a8e..b8abff3 100755 --- a/pkg/api/url.go +++ b/pkg/api/url.go @@ -7,6 +7,7 @@ func Add(router *mux.Router, switcher Switcher) { User{}.Router(router) Bgp{}.Router(router) IPSec{}.Router(router) + Prefix{}.Router(router) Neighbor{}.Router(router) Access{}.Router(router) OnLine{}.Router(router) diff --git a/pkg/api/ztrust.go b/pkg/api/ztrust.go index 21a6f67..5e3c2b6 100755 --- a/pkg/api/ztrust.go +++ b/pkg/api/ztrust.go @@ -55,7 +55,7 @@ func (h ZTrust) Enable(w http.ResponseWriter, r *http.Request) { http.Error(w, "Network not found", http.StatusBadRequest) return } - worker.DoZTrust() + worker.EnableZTrust() ResponseJson(w, "success") } @@ -68,7 +68,7 @@ func (h ZTrust) Disable(w http.ResponseWriter, r *http.Request) { http.Error(w, "Network not found", http.StatusBadRequest) return } - worker.UndoZTrust() + worker.DisableZTrust() ResponseJson(w, "success") } diff --git a/pkg/libol/nl_linux.go b/pkg/libol/nl_linux.go index d337541..ee8b39b 100755 --- a/pkg/libol/nl_linux.go +++ b/pkg/libol/nl_linux.go @@ -1,8 +1,9 @@ package libol import ( - "github.com/vishvananda/netlink" "net" + + "github.com/vishvananda/netlink" ) func GetLocalByGw(addr string) (net.IP, error) { @@ -43,3 +44,45 @@ func GetLocalByGw(addr string) (net.IP, error) { Info("GetLocalByGw: find %s on %s", addr, local) return local, nil } + +func ListRoutes() ([]Prefix, error) { + routes, err := netlink.RouteList(nil, netlink.FAMILY_V4) + if err != nil { + return nil, err + } + + var data []Prefix + for _, rte := range routes { + link, err := netlink.LinkByIndex(rte.LinkIndex) + if err != nil { + continue + } + + entry := Prefix{ + Protocol: rte.Protocol, + Priority: rte.Priority, + Link: link.Attrs().Name, + } + + if rte.Dst == nil { + entry.Dst = "0.0.0.0/0" + } else { + entry.Dst = rte.Dst.String() + } + + if len(rte.Gw) == 0 { + entry.Gw = "" + } else { + entry.Gw = rte.Gw.String() + } + + if len(rte.Src) == 0 { + entry.Src = "" + } else { + entry.Src = rte.Src.String() + } + + data = append(data, entry) + } + return data, nil +} diff --git a/pkg/libol/nl_others.go b/pkg/libol/nl_others.go index c295454..3b2d083 100755 --- a/pkg/libol/nl_others.go +++ b/pkg/libol/nl_others.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package libol @@ -7,3 +8,7 @@ import "net" func GetLocalByGw(addr string) (net.IP, error) { return nil, NewErr("GetLocalByGw notSupport") } + +func ListRoutes() ([]Prefix, error) { + return nil, NewErr("ListRoute notSupport") +} diff --git a/pkg/libol/struct.go b/pkg/libol/struct.go new file mode 100644 index 0000000..223d16a --- /dev/null +++ b/pkg/libol/struct.go @@ -0,0 +1,11 @@ +package libol + +type Prefix struct { + Link string + Dst string + Src string + Gw string + Protocol int + Priority int + Table int +} diff --git a/pkg/schema/network.go b/pkg/schema/network.go index 2b5ecc5..f49cbd1 100755 --- a/pkg/schema/network.go +++ b/pkg/schema/network.go @@ -10,9 +10,12 @@ type Lease struct { type PrefixRoute struct { Prefix string `json:"prefix"` - NextHop string `json:"nexthop"` - FindHop string `json:"findhop"` + NextHop string `json:"nexthop,omitempty"` + FindHop string `json:"findhop,omitempty"` Metric int `json:"metric"` + Link string `json:"link,omitempty"` + Table int `json:"table,omitempty"` + Source string `json:"source,omitempty"` MultiPath []MultiPath `json:"multipath,omitempty"` } diff --git a/pkg/switch/ipsec_linux.go b/pkg/switch/ipsec_linux.go index d42363f..74be8aa 100644 --- a/pkg/switch/ipsec_linux.go +++ b/pkg/switch/ipsec_linux.go @@ -313,7 +313,6 @@ func (w *IPSecWorker) RestartTunnel(data schema.IPSecTunnel) { func (w *IPSecWorker) ListTunnels(call func(obj schema.IPSecTunnel)) { status := w.Status() for _, tun := range w.spec.Tunnels { - state := status[tun.Name+"-c1"] obj := schema.IPSecTunnel{ Left: tun.Left, LeftId: tun.LeftId, @@ -323,7 +322,9 @@ func (w *IPSecWorker) ListTunnels(call func(obj schema.IPSecTunnel)) { RightPort: tun.RightPort, Secret: tun.Secret, Transport: tun.Transport, - State: state, + } + if state, ok := status[tun.Name+"-c1"]; ok { + obj.State = state } call(obj) } diff --git a/pkg/switch/network_linux.go b/pkg/switch/network_linux.go index 843cf77..a58502e 100755 --- a/pkg/switch/network_linux.go +++ b/pkg/switch/network_linux.go @@ -386,33 +386,33 @@ func (w *WorkerImpl) SetMss(mss int) { } } -func (w *WorkerImpl) doSnat() { +func (w *WorkerImpl) enableSnat() { w.fire.Nat.Post.AddRuleX(cn.IPRule{ Jump: w.snat.Chain().Name, Comment: "Goto SNAT", }) } -func (w *WorkerImpl) undoSnat() { +func (w *WorkerImpl) disableSnat() { w.fire.Nat.Post.DelRuleX(cn.IPRule{ Jump: w.snat.Chain().Name, Comment: "Goto SNAT", }) } -func (w *WorkerImpl) DoSnat() { +func (w *WorkerImpl) EnableSnat() { cfg, _ := w.GetCfgs() if cfg.Snat == "disable" { cfg.Snat = "enable" - w.doSnat() + w.enableSnat() } } -func (w *WorkerImpl) UndoSnat() { +func (w *WorkerImpl) DisableSnat() { cfg, _ := w.GetCfgs() if cfg.Snat != "disable" { cfg.Snat = "disable" - w.undoSnat() + w.disableSnat() } } @@ -425,7 +425,7 @@ func (w *WorkerImpl) doTrust() { }) } -func (w *WorkerImpl) undoTrust() { +func (w *WorkerImpl) disableTrust() { _, vpn := w.GetCfgs() w.fire.Mangle.Pre.DelRuleX(cn.IPRule{ Input: vpn.Device, @@ -434,7 +434,7 @@ func (w *WorkerImpl) undoTrust() { }) } -func (w *WorkerImpl) DoZTrust() { +func (w *WorkerImpl) EnableZTrust() { cfg, _ := w.GetCfgs() if cfg.ZTrust != "enable" { cfg.ZTrust = "enable" @@ -442,11 +442,11 @@ func (w *WorkerImpl) DoZTrust() { } } -func (w *WorkerImpl) UndoZTrust() { +func (w *WorkerImpl) DisableZTrust() { cfg, _ := w.GetCfgs() if cfg.ZTrust == "enable" { cfg.ZTrust = "disable" - w.undoTrust() + w.disableTrust() } } @@ -515,7 +515,7 @@ func (w *WorkerImpl) Start(v api.Switcher) { w.fire.Start() w.snat.Install() if cfg.Snat != "disable" { - w.doSnat() + w.enableSnat() } if cfg.Bridge.Mss > 0 { // forward to remote @@ -603,7 +603,7 @@ func (w *WorkerImpl) Stop() { cfg, _ := w.GetCfgs() if cfg.Snat != "disable" { - w.undoSnat() + w.disableSnat() } w.snat.Cancel()