diff --git a/cmd/api/v5/cmd.go b/cmd/api/v5/cmd.go index 142b04e..ac9c381 100755 --- a/cmd/api/v5/cmd.go +++ b/cmd/api/v5/cmd.go @@ -29,21 +29,15 @@ func Commands(app *api.App) { app.Before = Before User{}.Commands(app) ACL{}.Commands(app) - Qos{}.Commands(app) Device{}.Commands(app) Lease{}.Commands(app) Config{}.Commands(app) - Point{}.Commands(app) - VPNClient{}.Commands(app) - Link{}.Commands(app) Server{}.Commands(app) Network{}.Commands(app) PProf{}.Commands(app) - VxLAN{}.Commands(app) + IPSec{}.Commands(app) Version{}.Commands(app) Log{}.Commands(app) Guest{}.Commands(app) Knock{}.Commands(app) - Output{}.Commands(app) - Route{}.Commands(app) } diff --git a/cmd/api/v5/ipsec.go b/cmd/api/v5/ipsec.go new file mode 100644 index 0000000..eca4fc4 --- /dev/null +++ b/cmd/api/v5/ipsec.go @@ -0,0 +1,121 @@ +package v5 + +import ( + "github.com/luscis/openlan/cmd/api" + "github.com/luscis/openlan/pkg/schema" + "github.com/urfave/cli/v2" +) + +type IPSec struct { + Cmd +} + +func (o IPSec) Commands(app *api.App) { + tunnel := IPSecTunnel{} + app.Command(&cli.Command{ + Name: "ipsec", + Usage: "IPSec configuration", + Subcommands: []*cli.Command{ + tunnel.Commands(), + }, + }) +} + +type IPSecTunnel struct { + Cmd +} + +func (o IPSecTunnel) Url(prefix string) string { + return prefix + "/api/network/ipsec/tunnel" +} + +func (o IPSecTunnel) Add(c *cli.Context) error { + output := &schema.IPSecTunnel{ + Right: c.String("remote"), + Secret: c.String("secret"), + Transport: c.String("transport"), + LeftId: c.String("localid"), + RightId: c.String("remoteid"), + LeftPort: c.Int("localport"), + RightPort: c.Int("remoteport"), + } + url := o.Url(c.String("url")) + clt := o.NewHttp(c.String("token")) + if err := clt.PostJSON(url, output, nil); err != nil { + return err + } + return nil +} + +func (o IPSecTunnel) Remove(c *cli.Context) error { + output := &schema.IPSecTunnel{ + Right: c.String("remote"), + Transport: c.String("transport"), + } + url := o.Url(c.String("url")) + clt := o.NewHttp(c.String("token")) + if err := clt.DeleteJSON(url, output, nil); err != nil { + return err + } + return nil +} + +func (o IPSecTunnel) Tmpl() string { + return `# total {{ len . }} +{{ps -15 "Right"}} {{ps -15 "Transport"}} {{ps -15 "Secret"}} {{ps -15 "Port"}} {{ps -15 "Connection"}} +{{- range . }} +{{ps -15 .Right}} {{ps -15 .Transport }} {{ps -15 .Secret}} {{.LeftPort}}-{{.RightPort}} {{.LeftId}}-{{.RightId}} +{{- end }} +` +} + +func (o IPSecTunnel) List(c *cli.Context) error { + url := o.Url(c.String("url")) + clt := o.NewHttp(c.String("token")) + var items []schema.IPSecTunnel + if err := clt.GetJSON(url, &items); err != nil { + return err + } + return o.Out(items, c.String("format"), o.Tmpl()) +} + +func (o IPSecTunnel) Commands() *cli.Command { + return &cli.Command{ + Name: "tunnel", + Aliases: []string{"tun"}, + Usage: "IPSec Tunnel configuration", + Subcommands: []*cli.Command{ + { + Name: "add", + Usage: "Add a tunnel for the network", + Flags: []cli.Flag{ + &cli.StringFlag{Name: "remote", Required: true}, + &cli.StringFlag{Name: "remoteid"}, + &cli.IntFlag{Name: "remoteport"}, + &cli.StringFlag{Name: "transport", Required: true}, + &cli.StringFlag{Name: "secret", Required: true}, + &cli.StringFlag{Name: "localid"}, + &cli.IntFlag{Name: "localport"}, + }, + Action: o.Add, + }, + { + Name: "remove", + Usage: "Remove a tunnel from the network", + Aliases: []string{"rm"}, + Flags: []cli.Flag{ + &cli.StringFlag{Name: "remote", Required: true}, + &cli.StringFlag{Name: "transport", Required: true}, + }, + Action: o.Remove, + }, + { + Name: "list", + Usage: "Display all tunnel of the network", + Aliases: []string{"ls"}, + Flags: []cli.Flag{}, + Action: o.List, + }, + }, + } +} diff --git a/cmd/api/v5/link.go b/cmd/api/v5/link.go index 3441839..c37c29a 100755 --- a/cmd/api/v5/link.go +++ b/cmd/api/v5/link.go @@ -1,7 +1,6 @@ package v5 import ( - "github.com/luscis/openlan/cmd/api" "github.com/luscis/openlan/pkg/schema" "github.com/urfave/cli/v2" ) @@ -34,7 +33,7 @@ func (u Link) List(c *cli.Context) error { if err := clt.GetJSON(url, &items); err != nil { return err } - name := c.String("network") + name := c.String("name") if len(name) > 0 { tmp := items[:0] for _, obj := range items { @@ -47,21 +46,17 @@ func (u Link) List(c *cli.Context) error { return u.Out(items, c.String("format"), u.Tmpl()) } -func (u Link) Commands(app *api.App) { - app.Command(&cli.Command{ - Name: "link", - Aliases: []string{"ln"}, - Usage: "Link connect to others", +func (u Link) Commands() *cli.Command { + return &cli.Command{ + Name: "link", + Usage: "Link connect to others", Subcommands: []*cli.Command{ { Name: "list", Usage: "Display all links", Aliases: []string{"ls"}, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "network"}, - }, - Action: u.List, + Action: u.List, }, }, - }) + } } diff --git a/cmd/api/v5/network.go b/cmd/api/v5/network.go index 1d2b1b7..7f449cd 100755 --- a/cmd/api/v5/network.go +++ b/cmd/api/v5/network.go @@ -86,20 +86,26 @@ func (u Network) Save(c *cli.Context) error { } func (u Network) Commands(app *api.App) { + point := Point{} + client := VPNClient{} + route := Route{} + link := Link{} openvpn := OpenVpn{} + output := Output{} + qos := Qos{} app.Command(&cli.Command{ Name: "network", Aliases: []string{"net"}, - Usage: "Logical network", + Flags: []cli.Flag{ + &cli.StringFlag{Name: "name", Value: ""}, + }, + Usage: "Logical network", Subcommands: []*cli.Command{ { Name: "list", Usage: "Display all network", Aliases: []string{"ls"}, Action: u.List, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "name"}, - }, }, { Name: "add", @@ -113,60 +119,21 @@ func (u Network) Commands(app *api.App) { Name: "remove", Usage: "Remove the network", Aliases: []string{"rm"}, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "name"}, - }, - Action: u.Remove, + Action: u.Remove, }, { Name: "save", Usage: "Save the network", Aliases: []string{"sa"}, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "name", Value: ""}, - }, - Action: u.Save, + Action: u.Save, }, + point.Commands(), + qos.Commands(), + client.Commands(), openvpn.Commands(), + output.Commands(), + route.Commands(), + link.Commands(), }, }) } - -type OpenVpn struct { - Cmd -} - -func (o OpenVpn) Url(prefix, name string) string { - return prefix + "/api/network/" + name + "/openvpn/restart" -} - -func (o OpenVpn) Restart(c *cli.Context) error { - network := c.String("network") - url := o.Url(c.String("url"), network) - - clt := o.NewHttp(c.String("token")) - if err := clt.PostJSON(url, nil, nil); err != nil { - return err - } - - return nil -} - -func (o OpenVpn) Commands() *cli.Command { - return &cli.Command{ - Name: "openvpn", - Usage: "control openvpn", - Aliases: []string{"ov"}, - Subcommands: []*cli.Command{ - { - Name: "restart", - Usage: "restart openvpn for the network", - Aliases: []string{"ro"}, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "network", Required: true}, - }, - Action: o.Restart, - }, - }, - } -} diff --git a/cmd/api/v5/openvpn.go b/cmd/api/v5/openvpn.go index f1e687d..2e66ee2 100755 --- a/cmd/api/v5/openvpn.go +++ b/cmd/api/v5/openvpn.go @@ -1,7 +1,6 @@ package v5 import ( - "github.com/luscis/openlan/cmd/api" "github.com/luscis/openlan/pkg/schema" "github.com/urfave/cli/v2" ) @@ -28,13 +27,13 @@ func (u VPNClient) Tmpl() string { } func (u VPNClient) List(c *cli.Context) error { - url := u.Url(c.String("url"), c.String("network")) + url := u.Url(c.String("url"), c.String("name")) clt := u.NewHttp(c.String("token")) var items []schema.VPNClient if err := clt.GetJSON(url, &items); err != nil { return err } - name := c.String("network") + name := c.String("name") if len(name) > 0 { tmp := items[:0] for _, obj := range items { @@ -47,21 +46,52 @@ func (u VPNClient) List(c *cli.Context) error { return u.Out(items, c.String("format"), u.Tmpl()) } -func (u VPNClient) Commands(app *api.App) { - app.Command(&cli.Command{ - Name: "client", - Aliases: []string{"cl"}, - Usage: "Connected client by OpenVPN", +func (u VPNClient) Commands() *cli.Command { + return &cli.Command{ + Name: "client", + Usage: "Clients by OpenVPN", Subcommands: []*cli.Command{ { Name: "list", Usage: "Display all clients", Aliases: []string{"ls"}, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "network"}, - }, - Action: u.List, + Action: u.List, }, }, - }) + } +} + +type OpenVpn struct { + Cmd +} + +func (o OpenVpn) Url(prefix, name string) string { + return prefix + "/api/network/" + name + "/openvpn/restart" +} + +func (o OpenVpn) Restart(c *cli.Context) error { + network := c.String("name") + url := o.Url(c.String("url"), network) + + clt := o.NewHttp(c.String("token")) + if err := clt.PostJSON(url, nil, nil); err != nil { + return err + } + + return nil +} + +func (o OpenVpn) Commands() *cli.Command { + return &cli.Command{ + Name: "openvpn", + Usage: "Control OpenVPN", + Subcommands: []*cli.Command{ + { + Name: "restart", + Usage: "restart openvpn for the network", + Aliases: []string{"ro"}, + Action: o.Restart, + }, + }, + } } diff --git a/cmd/api/v5/output.go b/cmd/api/v5/output.go index 106a03f..4f636da 100644 --- a/cmd/api/v5/output.go +++ b/cmd/api/v5/output.go @@ -1,7 +1,6 @@ package v5 import ( - "github.com/luscis/openlan/cmd/api" "github.com/luscis/openlan/pkg/libol" "github.com/luscis/openlan/pkg/schema" "github.com/urfave/cli/v2" @@ -16,7 +15,7 @@ func (o Output) Url(prefix, name string) string { } func (o Output) Add(c *cli.Context) error { - network := c.String("network") + network := c.String("name") if len(network) == 0 { return libol.NewErr("invalid network") } @@ -37,7 +36,7 @@ func (o Output) Add(c *cli.Context) error { } func (o Output) Remove(c *cli.Context) error { - network := c.String("network") + network := c.String("name") if len(network) == 0 { return libol.NewErr("invalid network") } @@ -54,7 +53,7 @@ func (o Output) Remove(c *cli.Context) error { } func (o Output) Save(c *cli.Context) error { - network := c.String("network") + network := c.String("name") url := o.Url(c.String("url"), network) clt := o.NewHttp(c.String("token")) @@ -75,7 +74,7 @@ func (o Output) Tmpl() string { } func (o Output) List(c *cli.Context) error { - url := o.Url(c.String("url"), c.String("network")) + url := o.Url(c.String("url"), c.String("name")) clt := o.NewHttp(c.String("token")) var items []schema.Output if err := clt.GetJSON(url, &items); err != nil { @@ -84,23 +83,19 @@ func (o Output) List(c *cli.Context) error { return o.Out(items, c.String("format"), o.Tmpl()) } -func (o Output) Commands(app *api.App) { - app.Command(&cli.Command{ - Name: "output", - Aliases: []string{"op"}, - Usage: "Output configuration", +func (o Output) Commands() *cli.Command { + return &cli.Command{ + Name: "output", + Usage: "Output configuration", Subcommands: []*cli.Command{ { Name: "add", Usage: "Add an output for the network", Flags: []cli.Flag{ - &cli.StringFlag{Name: "network"}, - &cli.StringFlag{Name: "remote"}, + &cli.StringFlag{Name: "remote", Required: true}, &cli.IntFlag{Name: "segment"}, &cli.StringFlag{Name: "protocol"}, &cli.StringFlag{Name: "dstport"}, - //&cli.StringFlag{Name: "connection"}, - &cli.StringFlag{Name: "secret"}, }, Action: o.Add, }, @@ -109,8 +104,7 @@ func (o Output) Commands(app *api.App) { Usage: "Remove an output from the network", Aliases: []string{"rm"}, Flags: []cli.Flag{ - &cli.StringFlag{Name: "network"}, - &cli.StringFlag{Name: "device"}, + &cli.StringFlag{Name: "device", Required: true}, }, Action: o.Remove, }, @@ -118,20 +112,14 @@ func (o Output) Commands(app *api.App) { Name: "list", Usage: "Display all outputs of the network", Aliases: []string{"ls"}, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "network", Required: true}, - }, - Action: o.List, + Action: o.List, }, { Name: "save", Usage: "Save all outputs", Aliases: []string{"sa"}, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "network", Required: true}, - }, - Action: o.Save, + Action: o.Save, }, }, - }) + } } diff --git a/cmd/api/v5/point.go b/cmd/api/v5/point.go index a6ab744..4f40f00 100755 --- a/cmd/api/v5/point.go +++ b/cmd/api/v5/point.go @@ -1,7 +1,6 @@ package v5 import ( - "github.com/luscis/openlan/cmd/api" "github.com/luscis/openlan/pkg/schema" "github.com/urfave/cli/v2" ) @@ -34,7 +33,7 @@ func (u Point) List(c *cli.Context) error { if err := clt.GetJSON(url, &items); err != nil { return err } - name := c.String("network") + name := c.String("name") if len(name) > 0 { tmp := items[:0] for _, obj := range items { @@ -47,21 +46,17 @@ func (u Point) List(c *cli.Context) error { return u.Out(items, c.String("format"), u.Tmpl()) } -func (u Point) Commands(app *api.App) { - app.Command(&cli.Command{ - Name: "point", - Aliases: []string{"ap"}, - Usage: "Point accessed to switch", +func (u Point) Commands() *cli.Command { + return &cli.Command{ + Name: "point", + Usage: "Point accessed to switch", Subcommands: []*cli.Command{ { Name: "list", Usage: "Display all points", Aliases: []string{"ls"}, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "network"}, - }, - Action: u.List, + Action: u.List, }, }, - }) + } } diff --git a/cmd/api/v5/qos.go b/cmd/api/v5/qos.go index feeb680..0983235 100644 --- a/cmd/api/v5/qos.go +++ b/cmd/api/v5/qos.go @@ -1,7 +1,6 @@ package v5 import ( - "github.com/luscis/openlan/cmd/api" "github.com/luscis/openlan/pkg/schema" "github.com/urfave/cli/v2" ) @@ -10,18 +9,15 @@ type Qos struct { Cmd } -func (q Qos) Commands(app *api.App) { +func (q Qos) Commands() *cli.Command { rule := QosRule{} - app.Command(&cli.Command{ + return &cli.Command{ Name: "qos", - Usage: "qos for client in network", - Flags: []cli.Flag{ - &cli.StringFlag{Name: "name", Aliases: []string{"n"}}, - }, + Usage: "QoS for client in network", Subcommands: []*cli.Command{ rule.Commands(), }, - }) + } } type QosRule struct { diff --git a/cmd/api/v5/route.go b/cmd/api/v5/route.go index 7edf223..d596f34 100644 --- a/cmd/api/v5/route.go +++ b/cmd/api/v5/route.go @@ -1,7 +1,6 @@ package v5 import ( - "github.com/luscis/openlan/cmd/api" "github.com/luscis/openlan/pkg/libol" "github.com/luscis/openlan/pkg/schema" "github.com/urfave/cli/v2" @@ -16,7 +15,7 @@ func (r Route) Url(prefix, name string) string { } func (r Route) Add(c *cli.Context) error { - network := c.String("network") + network := c.String("name") if len(network) == 0 { return libol.NewErr("invalid network") } @@ -35,7 +34,7 @@ func (r Route) Add(c *cli.Context) error { } func (r Route) Remove(c *cli.Context) error { - network := c.String("network") + network := c.String("name") if len(network) == 0 { return libol.NewErr("invalid network") } @@ -54,7 +53,7 @@ func (r Route) Remove(c *cli.Context) error { } func (r Route) Save(c *cli.Context) error { - network := c.String("network") + network := c.String("name") url := r.Url(c.String("url"), network) clt := r.NewHttp(c.String("token")) @@ -75,7 +74,7 @@ func (r Route) Tmpl() string { } func (r Route) List(c *cli.Context) error { - url := r.Url(c.String("url"), c.String("network")) + url := r.Url(c.String("url"), c.String("name")) clt := r.NewHttp(c.String("token")) var items []schema.PrefixRoute if err := clt.GetJSON(url, &items); err != nil { @@ -84,18 +83,16 @@ func (r Route) List(c *cli.Context) error { return r.Out(items, c.String("format"), r.Tmpl()) } -func (r Route) Commands(app *api.App) { - app.Command(&cli.Command{ - Name: "route", - Aliases: []string{"op"}, - Usage: "Route configuration", +func (r Route) Commands() *cli.Command { + return &cli.Command{ + Name: "route", + Usage: "Route configuration", Subcommands: []*cli.Command{ { Name: "add", Usage: "Add a route for the network", Flags: []cli.Flag{ - &cli.StringFlag{Name: "network", Required: true}, - &cli.StringFlag{Name: "prefix"}, + &cli.StringFlag{Name: "prefix", Required: true}, &cli.StringFlag{Name: "nexthop"}, &cli.IntFlag{Name: "metric"}, &cli.StringFlag{Name: "mode"}, @@ -107,8 +104,7 @@ func (r Route) Commands(app *api.App) { Usage: "Remove a route from the network", Aliases: []string{"rm"}, Flags: []cli.Flag{ - &cli.StringFlag{Name: "network", Required: true}, - &cli.StringFlag{Name: "prefix"}, + &cli.StringFlag{Name: "prefix", Required: true}, &cli.StringFlag{Name: "nexthop"}, }, Action: r.Remove, @@ -117,20 +113,14 @@ func (r Route) Commands(app *api.App) { Name: "list", Usage: "Display all outputs of the network", Aliases: []string{"ls"}, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "network", Required: true}, - }, - Action: r.List, + Action: r.List, }, { Name: "save", Usage: "Save all routes", Aliases: []string{"sa"}, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "network", Required: true}, - }, - Action: r.Save, + Action: r.Save, }, }, - }) + } } diff --git a/cmd/api/v5/vxlan.go b/cmd/api/v5/vxlan.go deleted file mode 100755 index 10a42f3..0000000 --- a/cmd/api/v5/vxlan.go +++ /dev/null @@ -1,54 +0,0 @@ -package v5 - -import ( - "github.com/luscis/openlan/cmd/api" - "github.com/luscis/openlan/pkg/schema" - "github.com/urfave/cli/v2" -) - -type VxLAN struct { - Cmd -} - -func (u VxLAN) Url(prefix, name string) string { - if name == "" { - return prefix + "/api/vxlan" - } else { - return prefix + "/api/vxlan/" + name - } -} - -func (u VxLAN) Tmpl() string { - return `# total {{ len . }} -{{ps -16 "name"}} {{ps -15 "bridge"}} {{ ps -16 "address" }} {{ps -16 "vni"}} {{ps -16 "local"}} {{ps -22 "remote"}} -{{- range . }} -{{ps -16 .UUID}} {{pt .AliveTime | ps -8}} {{ ps -8 .Device}} {{ps -16 .Alias}} {{ps -8 .User}} {{ps -22 .Remote}} -{{- end }} -` -} - -func (u VxLAN) List(c *cli.Context) error { - url := u.Url(c.String("url"), "") - clt := u.NewHttp(c.String("token")) - var items []schema.VxLAN - if err := clt.GetJSON(url, &items); err != nil { - return err - } - return u.Out(items, c.String("format"), u.Tmpl()) -} - -func (u VxLAN) Commands(app *api.App) { - app.Command(&cli.Command{ - Name: "vxlan", - Aliases: []string{"vx"}, - Usage: "VxLAN configuration", - Subcommands: []*cli.Command{ - { - Name: "list", - Usage: "Display all vxlan", - Aliases: []string{"ls"}, - Action: u.List, - }, - }, - }) -} diff --git a/pkg/api/api.go b/pkg/api/api.go index 57aaf0c..b2da281 100755 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -70,7 +70,7 @@ type Qoser interface { type Outputer interface { AddOutput(data schema.Output) - DelOutput(device string) + DelOutput(data schema.Output) SaveOutput() } diff --git a/pkg/api/ipsec.go b/pkg/api/ipsec.go new file mode 100755 index 0000000..0e8848b --- /dev/null +++ b/pkg/api/ipsec.go @@ -0,0 +1,60 @@ +package api + +import ( + "net/http" + + "github.com/gorilla/mux" + "github.com/luscis/openlan/pkg/libol" + "github.com/luscis/openlan/pkg/schema" +) + +type IPSec struct { + Switcher Switcher +} + +func (h IPSec) Router(router *mux.Router) { + router.HandleFunc("/api/network/ipsec/tunnel", h.Get).Methods("GET") + router.HandleFunc("/api/network/ipsec/tunnel", h.Post).Methods("POST") + router.HandleFunc("/api/network/ipsec/tunnel", h.Delete).Methods("DELETE") +} + +func (h IPSec) Get(w http.ResponseWriter, r *http.Request) { + libol.Debug("IPSec.Get %s") + tunnels := make([]schema.IPSecTunnel, 0, 1024) + if Call.secer == nil { + http.Error(w, "network is nil", http.StatusBadRequest) + return + } + Call.secer.ListTunnels(func(obj schema.IPSecTunnel) { + tunnels = append(tunnels, obj) + }) + ResponseJson(w, tunnels) +} + +func (h IPSec) Post(w http.ResponseWriter, r *http.Request) { + tun := &schema.IPSecTunnel{} + if err := GetData(r, tun); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if Call.secer == nil { + http.Error(w, "network is nil", http.StatusBadRequest) + return + } + Call.secer.AddTunnel(*tun) + ResponseMsg(w, 0, "") +} + +func (h IPSec) Delete(w http.ResponseWriter, r *http.Request) { + tun := &schema.IPSecTunnel{} + if err := GetData(r, tun); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if Call.secer == nil { + http.Error(w, "network is nil", http.StatusBadRequest) + return + } + Call.secer.DelTunnel(*tun) + ResponseMsg(w, 0, "") +} diff --git a/pkg/api/output.go b/pkg/api/output.go index 7c54d8e..791a504 100755 --- a/pkg/api/output.go +++ b/pkg/api/output.go @@ -78,7 +78,7 @@ func (h Output) Delete(w http.ResponseWriter, r *http.Request) { http.Error(w, "network not found", http.StatusBadRequest) return } - worker.DelOutput(output.Device) + worker.DelOutput(*output) ResponseMsg(w, 0, "") } diff --git a/pkg/api/url.go b/pkg/api/url.go index 09e20e3..5dca04e 100755 --- a/pkg/api/url.go +++ b/pkg/api/url.go @@ -24,4 +24,5 @@ func Add(router *mux.Router, switcher Switcher) { Output{Switcher: switcher}.Router(router) ACL{}.Router(router) Route{Switcher: switcher}.Router(router) + IPSec{}.Router(router) } diff --git a/pkg/config/ipsec.go b/pkg/config/ipsec.go index 23eb887..9735276 100644 --- a/pkg/config/ipsec.go +++ b/pkg/config/ipsec.go @@ -6,10 +6,10 @@ type IPSecTunnel struct { Name string `json:"-"` Left string `json:"local"` LeftId string `json:"localid"` - LeftPort string `json:"localport"` + LeftPort int `json:"localport"` Right string `json:"remote"` RightId string `json:"remoteid"` - RightPort string `json:"remoteport"` + RightPort int `json:"remoteport"` Transport string `json:"transport"` Secret string `json:"secret"` } @@ -36,10 +36,27 @@ func (s *IPSecSpecifies) Correct() { } } -func (s *IPSecSpecifies) AddTunnel(data *IPSecTunnel) { - +func (s *IPSecSpecifies) FindTunnel(value *IPSecTunnel) (*IPSecTunnel, int) { + for index, obj := range s.Tunnels { + if obj.Id() == value.Id() { + return obj, index + } + } + return nil, -1 } -func (s *IPSecSpecifies) DelTunnel(data *IPSecTunnel) { +func (s *IPSecSpecifies) AddTunnel(value *IPSecTunnel) bool { + _, find := s.FindTunnel(value) + if find == -1 { + s.Tunnels = append(s.Tunnels, value) + } + return find == -1 +} +func (s *IPSecSpecifies) DelTunnel(value *IPSecTunnel) (*IPSecTunnel, bool) { + obj, find := s.FindTunnel(value) + if find != -1 { + s.Tunnels = append(s.Tunnels[:find], s.Tunnels[find+1:]...) + } + return obj, find != -1 } diff --git a/pkg/config/network.go b/pkg/config/network.go index 267bc93..6233533 100755 --- a/pkg/config/network.go +++ b/pkg/config/network.go @@ -22,7 +22,7 @@ type Network struct { Acl string `json:"acl,omitempty"` Specifies interface{} `json:"specifies,omitempty"` Dhcp string `json:"dhcp,omitempty"` - Outputs []Output `json:"outputs,omitempty"` + Outputs []*Output `json:"outputs,omitempty"` ZTrust string `json:"ztrust,omitempty"` Qos string `json:"qos,omitempty"` Namespace string `json:"namespace,omitempty"` @@ -185,3 +185,56 @@ func (n *Network) SaveNextGroup() { func (n *Network) Reload() { } + +func (n *Network) FindRoute(value PrefixRoute) (PrefixRoute, int) { + for i, obj := range n.Routes { + if value.Prefix == obj.Prefix { + return obj, i + } + } + return PrefixRoute{}, -1 +} + +func (n *Network) AddRoute(value PrefixRoute) bool { + _, index := n.FindRoute(value) + if index == -1 { + n.Routes = append(n.Routes, value) + } + return index == -1 +} + +func (n *Network) DelRoute(value PrefixRoute) (PrefixRoute, bool) { + obj, index := n.FindRoute(value) + if index != -1 { + n.Routes = append(n.Routes[:index], n.Routes[index+1:]...) + } + return obj, index != -1 +} + +func (n *Network) FindOutput(value *Output) (*Output, int) { + for i, obj := range n.Outputs { + if value.Link != "" && value.Link == obj.Link { + return obj, i + } + if value.Link == "" && value.Id() == obj.Id() { + return obj, i + } + } + return nil, -1 +} + +func (n *Network) AddOutput(value *Output) bool { + _, index := n.FindOutput(value) + if index == -1 { + n.Outputs = append(n.Outputs, value) + } + return index == -1 +} + +func (n *Network) DelOutput(value *Output) (*Output, bool) { + obj, index := n.FindOutput(value) + if index != -1 { + n.Outputs = append(n.Outputs[:index], n.Outputs[index+1:]...) + } + return obj, index != -1 +} diff --git a/pkg/config/output.go b/pkg/config/output.go index f55e5c1..63fac91 100755 --- a/pkg/config/output.go +++ b/pkg/config/output.go @@ -1,5 +1,7 @@ package config +import "fmt" + type Output struct { Segment int `json:"segment"` Protocol string `json:"protocol,omitempty"` // gre, vxlan, etc. @@ -8,3 +10,21 @@ type Output struct { Link string `json:"link,omitempty"` // link name Secret string `json:"secret"` } + +func (o *Output) Id() string { + return fmt.Sprintf("%s-%s-%d", o.Protocol, o.Remote, o.Segment) +} + +func (o *Output) GenName() { + if o.Link == "" { + if o.Protocol == "gre" { + o.Link = fmt.Sprintf("%s%d", "gre", o.Segment) + } else if o.Protocol == "vxlan" { + o.Link = fmt.Sprintf("%s%d", "vxlan", o.Segment) + } else if o.Segment > 0 { + o.Link = fmt.Sprintf("%s.%d", o.Remote, o.Segment) + } else { + o.Link = o.Remote + } + } +} diff --git a/pkg/schema/ipsec.go b/pkg/schema/ipsec.go index fefb9ec..f6fb6c3 100644 --- a/pkg/schema/ipsec.go +++ b/pkg/schema/ipsec.go @@ -3,10 +3,10 @@ package schema type IPSecTunnel struct { Left string `json:"local"` LeftId string `json:"localid"` - LeftPort string `json:"localport"` + LeftPort int `json:"localport"` Right string `json:"remote"` RightId string `json:"remoteid"` - RightPort string `json:"remoteport"` + RightPort int `json:"remoteport"` Transport string `json:"transport"` Secret string `json:"secret"` } diff --git a/pkg/switch/ipsec.go b/pkg/switch/ipsec.go index 0db4309..4f197d0 100644 --- a/pkg/switch/ipsec.go +++ b/pkg/switch/ipsec.go @@ -113,35 +113,35 @@ func (w *IPSecWorker) startConn(name string) { }) } -func (w *IPSecWorker) addTunnel(tunnel *co.IPSecTunnel) error { +func (w *IPSecWorker) addTunnel(tun *co.IPSecTunnel) error { connTmpl := "" secTmpl := "" - name := tunnel.Name - if tunnel.Transport == "vxlan" { + name := tun.Name + if tun.Transport == "vxlan" { connTmpl = vxlanTmpl secTmpl = secretTmpl - } else if tunnel.Transport == "gre" { + } else if tun.Transport == "gre" { connTmpl = greTmpl secTmpl = secretTmpl } if secTmpl != "" { - if err := w.saveSec(name+".secrets", secTmpl, tunnel); err != nil { + if err := w.saveSec(name+".secrets", secTmpl, tun); err != nil { w.out.Error("WorkerImpl.AddTunnel %s", err) return err } libol.Exec("ipsec", "auto", "--rereadsecrets") } if connTmpl != "" { - if err := w.saveSec(name+".conf", connTmpl, tunnel); err != nil { + if err := w.saveSec(name+".conf", connTmpl, tun); err != nil { w.out.Error("WorkerImpl.AddTunnel %s", err) return err } - if tunnel.Transport == "vxlan" { + if tun.Transport == "vxlan" { w.startConn(name + "-c1") w.startConn(name + "-c2") - } else if tunnel.Transport == "gre" { + } else if tun.Transport == "gre" { w.startConn(name + "-c1") } } @@ -152,17 +152,17 @@ func (w *IPSecWorker) addTunnel(tunnel *co.IPSecTunnel) error { func (w *IPSecWorker) Start(v api.Switcher) { w.uuid = v.UUID() w.out.Info("IPSecWorker.Start") - for _, tunnel := range w.spec.Tunnels { - w.addTunnel(tunnel) + for _, tun := range w.spec.Tunnels { + w.addTunnel(tun) } } -func (w *IPSecWorker) removeTunnel(tunnel *co.IPSecTunnel) error { - name := tunnel.Name - if tunnel.Transport == "vxlan" { +func (w *IPSecWorker) removeTunnel(tun *co.IPSecTunnel) error { + name := tun.Name + if tun.Transport == "vxlan" { libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name+"-c1") libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name+"-c2") - } else if tunnel.Transport == "gre" { + } else if tun.Transport == "gre" { libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name+"-c1") } @@ -184,8 +184,8 @@ func (w *IPSecWorker) removeTunnel(tunnel *co.IPSecTunnel) error { func (w *IPSecWorker) Stop() { w.out.Info("IPSecWorker.Stop") - for _, tunnel := range w.spec.Tunnels { - w.removeTunnel(tunnel) + for _, tun := range w.spec.Tunnels { + w.removeTunnel(tun) } } @@ -198,12 +198,18 @@ func (w *IPSecWorker) Reload(v api.Switcher) { func (w *IPSecWorker) AddTunnel(data schema.IPSecTunnel) { cfg := &co.IPSecTunnel{ Left: data.Left, + LeftPort: data.LeftPort, + LeftId: data.LeftId, Right: data.Right, + RightPort: data.RightPort, + RightId: data.RightId, Secret: data.Secret, Transport: data.Transport, } - w.spec.AddTunnel(cfg) - w.addTunnel(cfg) + cfg.Correct() + if w.spec.AddTunnel(cfg) { + w.addTunnel(cfg) + } } func (w *IPSecWorker) DelTunnel(data schema.IPSecTunnel) { @@ -213,10 +219,24 @@ func (w *IPSecWorker) DelTunnel(data schema.IPSecTunnel) { Secret: data.Secret, Transport: data.Transport, } - w.removeTunnel(cfg) - w.spec.DelTunnel(cfg) + cfg.Correct() + if _, removed := w.spec.DelTunnel(cfg); removed { + w.removeTunnel(cfg) + } } func (w *IPSecWorker) ListTunnels(call func(obj schema.IPSecTunnel)) { - + for _, tun := range w.spec.Tunnels { + obj := schema.IPSecTunnel{ + Left: tun.Left, + LeftId: tun.LeftId, + LeftPort: tun.LeftPort, + Right: tun.Right, + RightId: tun.RightId, + RightPort: tun.RightPort, + Secret: tun.Secret, + Transport: tun.Transport, + } + call(obj) + } } diff --git a/pkg/switch/network.go b/pkg/switch/network.go index 1a120f7..07a696e 100755 --- a/pkg/switch/network.go +++ b/pkg/switch/network.go @@ -32,42 +32,11 @@ func NewNetworker(c *co.Network) api.Networker { return obj } -func toLinkName(protocol, remote string, segment int) string { - if protocol == "gre" { - return fmt.Sprintf("%s%d", "gre", segment) - } - if protocol == "vxlan" { - return fmt.Sprintf("%s%d", "vxlan", segment) - } - if segment > 0 { - return fmt.Sprintf("%s.%d", remote, segment) - } - return remote -} - -type LinuxPort struct { - output co.Output - link string -} - -func (l *LinuxPort) String() string { - return fmt.Sprintf("%s:%s:%d", l.output.Protocol, l.output.Remote, l.output.Segment) -} - -func (l *LinuxPort) GenName() { - if l.link != "" { - return - } - out := l.output - l.link = toLinkName(out.Protocol, out.Remote, out.Segment) -} - type WorkerImpl struct { uuid string cfg *co.Network out *libol.SubLogger dhcp *Dhcp - outputs []*LinuxPort fire *cn.FireWallTable setR *cn.IPSet setV *cn.IPSet @@ -184,70 +153,67 @@ func (w *WorkerImpl) AddPhysical(bridge string, output string) { } } -func (w *WorkerImpl) addOutput(bridge string, port *LinuxPort) { - cfg := port.output +func (w *WorkerImpl) addOutput(bridge string, port *co.Output) { mtu := 0 - if cfg.Protocol == "gre" { + if port.Protocol == "gre" { mtu = 1450 link := &nl.Gretap{ - IKey: uint32(cfg.Segment), - OKey: uint32(cfg.Segment), + IKey: uint32(port.Segment), + OKey: uint32(port.Segment), LinkAttrs: nl.LinkAttrs{ - Name: port.link, + Name: port.Link, MTU: mtu, }, Local: libol.ParseAddr("0.0.0.0"), - Remote: libol.ParseAddr(cfg.Remote), + Remote: libol.ParseAddr(port.Remote), PMtuDisc: 1, } if err := nl.LinkAdd(link); err != nil { - w.out.Error("WorkerImpl.LinkAdd %s %s", port.String(), err) + w.out.Error("WorkerImpl.LinkAdd %s %s", port.Id(), err) return } - } else if cfg.Protocol == "vxlan" { + } else if port.Protocol == "vxlan" { dport := 8472 - if cfg.DstPort > 0 { - dport = cfg.DstPort + if port.DstPort > 0 { + dport = port.DstPort } mtu = 1450 link := &nl.Vxlan{ - VxlanId: cfg.Segment, + VxlanId: port.Segment, LinkAttrs: nl.LinkAttrs{ TxQLen: -1, - Name: port.link, + Name: port.Link, MTU: mtu, }, - Group: libol.ParseAddr(cfg.Remote), + Group: libol.ParseAddr(port.Remote), Port: dport, } if err := nl.LinkAdd(link); err != nil { - w.out.Error("WorkerImpl.LinkAdd %s %s", port.String(), err) + w.out.Error("WorkerImpl.LinkAdd %s %s", port.Id(), err) return } } else { - link, err := nl.LinkByName(cfg.Remote) + link, err := nl.LinkByName(port.Remote) if link == nil { - w.out.Error("WorkerImpl.addOutput %s %s", cfg.Remote, err) + w.out.Error("WorkerImpl.addOutput %s %s", port.Remote, err) return } if err := nl.LinkSetUp(link); err != nil { - w.out.Warn("WorkerImpl.addOutput %s %s", cfg.Remote, err) + w.out.Warn("WorkerImpl.addOutput %s %s", port.Remote, err) } - if cfg.Segment > 0 { + if port.Segment > 0 { subLink := &nl.Vlan{ LinkAttrs: nl.LinkAttrs{ - Name: port.link, + Name: port.Link, ParentIndex: link.Attrs().Index, }, - VlanId: cfg.Segment, + VlanId: port.Segment, } if err := nl.LinkAdd(subLink); err != nil { w.out.Error("WorkerImpl.linkAdd %s %s", subLink.Name, err) return } - } else { - port.link = cfg.Remote } } @@ -260,16 +226,16 @@ func (w *WorkerImpl) addOutput(bridge string, port *LinuxPort) { out := &models.Output{ Network: w.cfg.Name, NewTime: time.Now().Unix(), - Protocol: cfg.Protocol, - Remote: cfg.Remote, - Segment: cfg.Segment, - Secret: cfg.Secret, - Device: port.link, + Protocol: port.Protocol, + Remote: port.Remote, + Segment: port.Segment, + Secret: port.Secret, + Device: port.Link, } - cache.Output.Add(port.link, out) + cache.Output.Add(port.Link, out) - w.out.Info("WorkerImpl.addOutput %s %s", port.link, port.String()) - w.AddPhysical(bridge, port.link) + w.out.Info("WorkerImpl.addOutput %s %s", port.Link, port.Id()) + w.AddPhysical(bridge, port.Link) } func (w *WorkerImpl) loadRoute(rt co.PrefixRoute) { @@ -401,12 +367,8 @@ func (w *WorkerImpl) Start(v api.Switcher) { } for _, output := range cfg.Outputs { - port := &LinuxPort{ - output: output, - } - port.GenName() - w.addOutput(cfg.Bridge.Name, port) - w.outputs = append(w.outputs, port) + output.GenName() + w.addOutput(cfg.Bridge.Name, output) } if !(w.dhcp == nil) { @@ -481,37 +443,36 @@ func (w *WorkerImpl) DelPhysical(bridge string, output string) { } } -func (w *WorkerImpl) delOutput(bridge string, port *LinuxPort) { - cfg := port.output - w.out.Info("WorkerImpl.delOutput %s %s", port.link, port.String()) +func (w *WorkerImpl) delOutput(bridge string, port *co.Output) { + w.out.Info("WorkerImpl.delOutput %s", port.Link) - cache.Output.Del(port.link) - w.DelPhysical(bridge, port.link) + cache.Output.Del(port.Link) + w.DelPhysical(bridge, port.Link) - if cfg.Protocol == "gre" { + if port.Protocol == "gre" { link := &nl.Gretap{ LinkAttrs: nl.LinkAttrs{ - Name: port.link, + Name: port.Link, }, } if err := nl.LinkDel(link); err != nil { w.out.Error("WorkerImpl.LinkDel %s %s", link.Name, err) return } - } else if cfg.Protocol == "vxlan" { + } else if port.Protocol == "vxlan" { link := &nl.Vxlan{ LinkAttrs: nl.LinkAttrs{ - Name: port.link, + Name: port.Link, }, } if err := nl.LinkDel(link); err != nil { w.out.Error("WorkerImpl.LinkDel %s %s", link.Name, err) return } - } else if port.output.Segment > 0 { + } else if port.Segment > 0 { link := &nl.Vlan{ LinkAttrs: nl.LinkAttrs{ - Name: port.link, + Name: port.Link, }, } @@ -584,10 +545,9 @@ func (w *WorkerImpl) Stop() { w.vrf.Down() } - for _, output := range w.outputs { + for _, output := range w.cfg.Outputs { w.delOutput(w.cfg.Bridge.Name, output) } - w.outputs = nil w.acl.Stop() @@ -1001,31 +961,18 @@ func (w *WorkerImpl) correctRoute(route *schema.PrefixRoute) co.PrefixRoute { Mode: route.Mode, Metric: route.Metric, } - rt.CorrectRoute(w.IfAddr()) - return rt } -func (w *WorkerImpl) findRoute(rt co.PrefixRoute) (co.PrefixRoute, int) { - for i, ert := range w.cfg.Routes { - if ert.Prefix == rt.Prefix { - return ert, i - } - } - return co.PrefixRoute{}, -1 -} - func (w *WorkerImpl) AddRoute(route *schema.PrefixRoute, switcher api.Switcher) error { rt := w.correctRoute(route) - if _, index := w.findRoute(rt); index != -1 { - w.out.Warn("WorkerImpl.AddRoute: route exist") + if !w.cfg.AddRoute(rt) { + w.out.Info("WorkerImpl.AddRoute: %s route exist", route.Prefix) return nil } - w.cfg.Routes = append(w.cfg.Routes, rt) w.out.Info("WorkerImpl.AddRoute: %v", rt) - w.addIpSet(rt) if inet, err := libol.ParseNet(rt.Prefix); err == nil { w.addVPNSet(inet.String()) @@ -1034,19 +981,17 @@ func (w *WorkerImpl) AddRoute(route *schema.PrefixRoute, switcher api.Switcher) w.addCacheRoute(rt) w.addVPNRoute(rt) w.loadRoute(rt) - return nil } func (w *WorkerImpl) DelRoute(route *schema.PrefixRoute, switcher api.Switcher) error { correctRt := w.correctRoute(route) - delRt, index := w.findRoute(correctRt) - if index == -1 { - w.out.Warn("WorkerImpl.DelRoute: route not found") + delRt, removed := w.cfg.DelRoute(correctRt) + if !removed { + w.out.Info("WorkerImpl.DelRoute: %s not found", route.Prefix) return nil } - w.cfg.Routes = append(w.cfg.Routes[:index], w.cfg.Routes[index+1:]...) w.delIpSet(delRt) if inet, err := libol.ParseNet(delRt.Prefix); err == nil { w.delVPNSet(inet.String()) @@ -1055,7 +1000,6 @@ func (w *WorkerImpl) DelRoute(route *schema.PrefixRoute, switcher api.Switcher) w.delCacheRoute(delRt) w.delVPNRoute(delRt) w.unloadRoute(delRt) - return nil } @@ -1085,48 +1029,28 @@ func (w *WorkerImpl) ACLer() api.ACLer { } func (w *WorkerImpl) AddOutput(data schema.Output) { - output := co.Output{ + output := &co.Output{ Segment: data.Segment, Protocol: data.Protocol, Remote: data.Remote, DstPort: data.DstPort, Secret: data.Secret, } - w.cfg.Outputs = append(w.cfg.Outputs, output) - port := &LinuxPort{ - output: output, + if !w.cfg.AddOutput(output) { + w.out.Info("WorkerImple.AddOutput %s already existed", output.Id()) + return } - port.GenName() - w.addOutput(w.cfg.Bridge.Name, port) - w.outputs = append(w.outputs, port) + output.GenName() + w.addOutput(w.cfg.Bridge.Name, output) } -func (w *WorkerImpl) DelOutput(device string) { - var port *LinuxPort - for _, v := range w.outputs { - if v.link == device { - port = v - break - } - } - if port == nil { +func (w *WorkerImpl) DelOutput(data schema.Output) { + output, removed := w.cfg.DelOutput(&co.Output{Link: data.Device}) + if !removed { + w.out.Info("WorkerImpl.DelOutput: %s not found", output.Id()) return } - Outputs := make([]co.Output, 0, len(w.cfg.Outputs)) - for _, v := range w.cfg.Outputs { - if v != port.output { - Outputs = append(Outputs, v) - } - } - w.cfg.Outputs = Outputs - w.delOutput(w.cfg.Bridge.Name, port) - outputs := make([]*LinuxPort, 0, len(w.outputs)) - for _, v := range w.outputs { - if v != port { - outputs = append(outputs, v) - } - } - w.outputs = outputs + w.delOutput(w.cfg.Bridge.Name, output) } func (w *WorkerImpl) SaveOutput() {