From caef90cc04945fd6eec7882b02437af4aa1bd95b Mon Sep 17 00:00:00 2001 From: Daniel Ding Date: Wed, 22 Oct 2025 10:48:56 +0800 Subject: [PATCH] fea: switch: do dnat. --- cmd/api/v5/network.go | 44 ++++++++--- pkg/api/acl.go | 2 +- pkg/api/api.go | 107 ++++++++++++++------------- pkg/api/bgp.go | 38 +++++----- pkg/api/config.go | 13 ++-- pkg/api/findhop.go | 2 +- pkg/api/ipsec.go | 18 ++--- pkg/api/link.go | 2 +- pkg/api/network.go | 89 ++++++++++++++++++++-- pkg/api/output.go | 6 +- pkg/api/qos.go | 12 +-- pkg/api/rate.go | 6 +- pkg/api/route.go | 6 +- pkg/api/server.go | 9 ++- pkg/api/url.go | 19 ++--- pkg/api/ztrust.go | 2 +- pkg/config/network.go | 10 +++ pkg/switch/bgp_linux.go | 4 +- pkg/switch/http.go | 10 +-- pkg/switch/ipsec_linux.go | 4 +- pkg/switch/network_linux.go | 142 ++++++++++++++++++++++++++++++------ pkg/switch/openlan_linux.go | 4 +- pkg/switch/router_linux.go | 4 +- pkg/switch/switch_linux.go | 4 +- 24 files changed, 382 insertions(+), 175 deletions(-) diff --git a/cmd/api/v5/network.go b/cmd/api/v5/network.go index 8211f06..25e5fa8 100755 --- a/cmd/api/v5/network.go +++ b/cmd/api/v5/network.go @@ -196,14 +196,16 @@ func (s SNAT) Commands() *cli.Command { Usage: "Configure SNAT", Subcommands: []*cli.Command{ { - Name: "enable", - Usage: "Enable snat", - Action: s.Enable, + Name: "enable", + Usage: "Enable snat", + Aliases: []string{"en"}, + Action: s.Enable, }, { - Name: "disable", - Usage: "Disable snat", - Action: s.Disable, + Name: "disable", + Usage: "Disable snat", + Aliases: []string{"dis"}, + Action: s.Disable, }, }, } @@ -251,16 +253,35 @@ func (s DNAT) Delete(c *cli.Context) error { return nil } +func (s DNAT) List(c *cli.Context) error { + url := s.Url(c.String("url"), c.String("name")) + clt := s.NewHttp(c.String("token")) + + var items []schema.DNAT + if err := clt.GetJSON(url, &items); err == nil { + return s.Out(items, c.String("format"), "") + } else { + return err + } + +} + func (s DNAT) Commands() *cli.Command { return &cli.Command{ Name: "dnat", Usage: "Configure DNAT", Subcommands: []*cli.Command{ + { + Name: "list", + Usage: "Liat all dnat", + Aliases: []string{"ls"}, + Action: s.List, + }, { Name: "add", Usage: "Add a dnat", Flags: []cli.Flag{ - &cli.StringFlag{Name: "protocol", Required: true}, + &cli.StringFlag{Name: "protocol", Value: "tcp"}, &cli.IntFlag{Name: "dport", Required: true}, &cli.StringFlag{Name: "dest", Required: true}, &cli.StringFlag{Name: "todest", Required: true}, @@ -269,14 +290,13 @@ func (s DNAT) Commands() *cli.Command { Action: s.Add, }, { - Name: "remove", - Usage: "Remove a snat", + Name: "remove", + Usage: "Remove a snat", + Aliases: []string{"rm"}, Flags: []cli.Flag{ - &cli.StringFlag{Name: "protocol", Required: true}, + &cli.StringFlag{Name: "protocol", Value: "tcp"}, &cli.IntFlag{Name: "dport", Required: true}, &cli.StringFlag{Name: "dest", Required: true}, - &cli.StringFlag{Name: "todest", Required: true}, - &cli.IntFlag{Name: "todport", Required: true}, }, Action: s.Delete, }, diff --git a/pkg/api/acl.go b/pkg/api/acl.go index 93a8b2b..9c9a597 100755 --- a/pkg/api/acl.go +++ b/pkg/api/acl.go @@ -8,7 +8,7 @@ import ( ) type ACL struct { - Switcher Switcher + SwitchApi SwitchApi } func (h ACL) Router(router *mux.Router) { diff --git a/pkg/api/api.go b/pkg/api/api.go index ee26ebc..e1501b4 100755 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -9,12 +9,12 @@ import ( "github.com/luscis/openlan/pkg/schema" ) -type Rater interface { +type RateApi interface { AddRate(device string, mbit int) DelRate(device string) } -type Switcher interface { +type SwitchApi interface { UUID() string UpTime() int64 Alias() string @@ -25,10 +25,10 @@ type Switcher interface { AddNetwork(network string) DelNetwork(network string) SaveNetwork(network string) - Rater + RateApi } -func NewWorkerSchema(s Switcher) schema.Worker { +func NewWorkerSchema(s SwitchApi) schema.Worker { protocol := "" if cfg := s.Config(); cfg != nil { protocol = cfg.Protocol @@ -41,14 +41,14 @@ func NewWorkerSchema(s Switcher) schema.Worker { } } -type ACLer interface { +type ACLApi interface { AddRule(rule *schema.ACLRule) error DelRule(rule *schema.ACLRule) error ListRules(call func(obj schema.ACLRule)) SaveRule() } -type ZTruster interface { +type ZTrustApi interface { AddGuest(name, source string) error DelGuest(name, source string) error Knock(name string, protocol, dest, port string, age int) error @@ -56,21 +56,21 @@ type ZTruster interface { ListKnock(name string, call func(obj schema.KnockRule)) } -type Router interface { - AddRoute(route *schema.PrefixRoute, switcher Switcher) error - DelRoute(route *schema.PrefixRoute, switcher Switcher) error +type RouteApi interface { + AddRoute(route *schema.PrefixRoute, switchApi SwitchApi) error + DelRoute(route *schema.PrefixRoute, switchApi SwitchApi) error ListRoute(call func(obj schema.PrefixRoute)) SaveRoute() } -type VPNer interface { +type VPNApi interface { StartVPN() AddVPNClient(name, local string) error DelVPNClient(name string) error ListClients(call func(name, local string)) } -type Qoser interface { +type QosApi interface { AddQos(name string, inSpeed float64) error UpdateQos(name string, inSpeed float64) error DelQos(name string) error @@ -78,57 +78,68 @@ type Qoser interface { SaveQos() } -type Outputer interface { +type OutputApi interface { AddOutput(data schema.Output) DelOutput(data schema.Output) SaveOutput() } -type FindHoper interface { +type FindHopApi interface { AddHop(data schema.FindHop) error DelHop(data schema.FindHop) error ListHop(call func(obj schema.FindHop)) SaveHop() } -type Super interface { +type SNATApi interface { + EnableSnat() + DisableSnat() +} + +type DNATApi interface { + AddDnat(data schema.DNAT) error + DelDnat(data schema.DNAT) error + ListDnat(call func(obj schema.DNAT)) +} + +type SupeApi interface { String() string ID() string Initialize() - Start(v Switcher) + Start(v SwitchApi) Stop() - Reload(v Switcher) + Reload(v SwitchApi) } -type Networker interface { - Super +type NetworkApi interface { + SupeApi Config() *co.Network Subnet() *net.IPNet Provider() string IfAddr() string SetMss(mss int) - Outputer - Router - VPNer + OutputApi + RouteApi + VPNApi Bridger() cn.Bridger - ZTruster() ZTruster - Qoser() Qoser - ACLer() ACLer - FindHoper() FindHoper + ZTruster() ZTrustApi + Qoser() QosApi + ACLer() ACLApi + FindHoper() FindHopApi EnableZTrust() DisableZTrust() - EnableSnat() - DisableSnat() + SNATApi + DNATApi } -type IPSecer interface { +type IPSecApi interface { AddTunnel(data schema.IPSecTunnel) DelTunnel(data schema.IPSecTunnel) StartTunnel(data schema.IPSecTunnel) ListTunnels(call func(obj schema.IPSecTunnel)) } -type Bgper interface { +type BgpApi interface { Enable(data schema.Bgp) Disable() Get() *schema.Bgp @@ -140,42 +151,34 @@ type Bgper interface { DelAdvertis(data schema.BgpPrefix) } -type APICall struct { - secer IPSecer - bgper Bgper - workers map[string]Networker +type callApi struct { + ipsecApi IPSecApi + bgpApi BgpApi + workers map[string]NetworkApi } -func (i *APICall) AddWorker(name string, obj Networker) { +func (i *callApi) AddWorker(name string, obj NetworkApi) { i.workers[name] = obj } -func (i *APICall) GetWorker(name string) Networker { +func (i *callApi) GetWorker(name string) NetworkApi { return i.workers[name] } -func (i *APICall) ListWorker(call func(w Networker)) { - for _, worker := range i.workers { - call(worker) +func (i *callApi) ListWorker(call func(w NetworkApi)) { + for _, w := range i.workers { + call(w) } } -func (i *APICall) SetIPSecer(value IPSecer) { - i.secer = value +func (i *callApi) SetIPSecer(value IPSecApi) { + i.ipsecApi = value } -func (i *APICall) GetIPSecer() IPSecer { - return i.secer +func (i *callApi) SetBgper(value BgpApi) { + i.bgpApi = value } -func (i *APICall) SetBgper(value Bgper) { - i.bgper = value -} - -func (i *APICall) GetBgper() Bgper { - return i.bgper -} - -var Call = &APICall{ - workers: make(map[string]Networker), +var Call = &callApi{ + workers: make(map[string]NetworkApi), } diff --git a/pkg/api/bgp.go b/pkg/api/bgp.go index b7f2bfd..b456714 100755 --- a/pkg/api/bgp.go +++ b/pkg/api/bgp.go @@ -9,7 +9,7 @@ import ( ) type Bgp struct { - Switcher Switcher + cs SwitchApi } func (h Bgp) Router(router *mux.Router) { @@ -26,11 +26,11 @@ func (h Bgp) Router(router *mux.Router) { func (h Bgp) Get(w http.ResponseWriter, r *http.Request) { libol.Debug("Bgp.Get %s") - if Call.bgper == nil { + if Call.bgpApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - data := Call.bgper.Get() + data := Call.bgpApi.Get() ResponseJson(w, data) } @@ -40,20 +40,20 @@ func (h Bgp) Post(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - if Call.bgper == nil { + if Call.bgpApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.bgper.Enable(data) + Call.bgpApi.Enable(data) ResponseMsg(w, 0, "") } func (h Bgp) Remove(w http.ResponseWriter, r *http.Request) { - if Call.bgper == nil { + if Call.bgpApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.bgper.Disable() + Call.bgpApi.Disable() ResponseMsg(w, 0, "") } @@ -63,11 +63,11 @@ func (h Bgp) RemoveNeighbor(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - if Call.bgper == nil { + if Call.bgpApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.bgper.DelNeighbor(nei) + Call.bgpApi.DelNeighbor(nei) ResponseMsg(w, 0, "") } @@ -77,11 +77,11 @@ func (h Bgp) AddNeighbor(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - if Call.bgper == nil { + if Call.bgpApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.bgper.AddNeighbor(nei) + Call.bgpApi.AddNeighbor(nei) ResponseMsg(w, 0, "") } @@ -91,11 +91,11 @@ func (h Bgp) RemoveAdvertis(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - if Call.bgper == nil { + if Call.bgpApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.bgper.DelAdvertis(data) + Call.bgpApi.DelAdvertis(data) ResponseMsg(w, 0, "") } @@ -105,11 +105,11 @@ func (h Bgp) AddAdvertis(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - if Call.bgper == nil { + if Call.bgpApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.bgper.AddAdvertis(data) + Call.bgpApi.AddAdvertis(data) ResponseMsg(w, 0, "") } @@ -119,11 +119,11 @@ func (h Bgp) RemoveReceivess(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - if Call.bgper == nil { + if Call.bgpApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.bgper.DelReceives(data) + Call.bgpApi.DelReceives(data) ResponseMsg(w, 0, "") } @@ -133,10 +133,10 @@ func (h Bgp) AddReceivess(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - if Call.bgper == nil { + if Call.bgpApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.bgper.AddReceives(data) + Call.bgpApi.AddReceives(data) ResponseMsg(w, 0, "") } diff --git a/pkg/api/config.go b/pkg/api/config.go index 73667ae..909fa05 100755 --- a/pkg/api/config.go +++ b/pkg/api/config.go @@ -1,12 +1,13 @@ package api import ( - "github.com/gorilla/mux" "net/http" + + "github.com/gorilla/mux" ) type Config struct { - Switcher Switcher + cs SwitchApi } func (c Config) Router(router *mux.Router) { @@ -18,18 +19,18 @@ func (c Config) Router(router *mux.Router) { func (c Config) List(w http.ResponseWriter, r *http.Request) { format := GetQueryOne(r, "format") if format == "yaml" { - ResponseYaml(w, c.Switcher.Config()) + ResponseYaml(w, c.cs.Config()) } else { - ResponseJson(w, c.Switcher.Config()) + ResponseJson(w, c.cs.Config()) } } func (c Config) Reload(w http.ResponseWriter, r *http.Request) { - c.Switcher.Reload() + c.cs.Reload() ResponseMsg(w, 0, "success") } func (c Config) Save(w http.ResponseWriter, r *http.Request) { - c.Switcher.Save() + c.cs.Save() ResponseMsg(w, 0, "success") } diff --git a/pkg/api/findhop.go b/pkg/api/findhop.go index 93dcd88..c5e156e 100644 --- a/pkg/api/findhop.go +++ b/pkg/api/findhop.go @@ -8,7 +8,7 @@ import ( ) type FindHop struct { - Switcher Switcher + cs SwitchApi } func (rt FindHop) Router(router *mux.Router) { diff --git a/pkg/api/ipsec.go b/pkg/api/ipsec.go index 70f5a77..711e21e 100755 --- a/pkg/api/ipsec.go +++ b/pkg/api/ipsec.go @@ -9,7 +9,7 @@ import ( ) type IPSec struct { - Switcher Switcher + cs SwitchApi } func (h IPSec) Router(router *mux.Router) { @@ -22,11 +22,11 @@ func (h IPSec) Router(router *mux.Router) { 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 { + if Call.ipsecApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.secer.ListTunnels(func(obj schema.IPSecTunnel) { + Call.ipsecApi.ListTunnels(func(obj schema.IPSecTunnel) { tunnels = append(tunnels, obj) }) ResponseJson(w, tunnels) @@ -38,11 +38,11 @@ func (h IPSec) Post(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - if Call.secer == nil { + if Call.ipsecApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.secer.AddTunnel(*tun) + Call.ipsecApi.AddTunnel(*tun) ResponseMsg(w, 0, "") } @@ -52,11 +52,11 @@ func (h IPSec) Delete(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - if Call.secer == nil { + if Call.ipsecApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.secer.DelTunnel(*tun) + Call.ipsecApi.DelTunnel(*tun) ResponseMsg(w, 0, "") } @@ -66,10 +66,10 @@ func (h IPSec) Start(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - if Call.secer == nil { + if Call.ipsecApi == nil { http.Error(w, "network is nil", http.StatusBadRequest) return } - Call.secer.StartTunnel(*tun) + Call.ipsecApi.StartTunnel(*tun) ResponseMsg(w, 0, "") } diff --git a/pkg/api/link.go b/pkg/api/link.go index d900d77..7d3139a 100755 --- a/pkg/api/link.go +++ b/pkg/api/link.go @@ -11,7 +11,7 @@ import ( ) type Link struct { - Switcher Switcher + cs SwitchApi } func (h Link) Router(router *mux.Router) { diff --git a/pkg/api/network.go b/pkg/api/network.go index ee9d35b..c93fb3b 100755 --- a/pkg/api/network.go +++ b/pkg/api/network.go @@ -12,7 +12,7 @@ import ( ) type Network struct { - Switcher Switcher + cs SwitchApi } func (h Network) Router(router *mux.Router) { @@ -23,7 +23,7 @@ func (h Network) Router(router *mux.Router) { router.HandleFunc("/api/network/{id}", h.Delete).Methods("DELETE") router.HandleFunc("/get/network/{id}/ovpn", h.Profile).Methods("GET") router.HandleFunc("/api/network/{id}/ovpn", h.Profile).Methods("GET") - router.HandleFunc("/api/network/{id}/openvpn/restart", h.RestartVPN).Methods("POST") + router.HandleFunc("/api/network/{id}/openvpn/restart", h.StartVPN).Methods("POST") } func (h Network) List(w http.ResponseWriter, r *http.Request) { @@ -58,7 +58,7 @@ func (h Network) Post(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - cs := h.Switcher.Config() + cs := h.cs.Config() obj, err := cs.AddNetwork(data) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) @@ -67,7 +67,7 @@ func (h Network) Post(w http.ResponseWriter, r *http.Request) { cs.CorrectNetwork(obj, "json") if obj := cs.GetNetwork(obj.Name); obj != nil { - h.Switcher.AddNetwork(obj.Name) + h.cs.AddNetwork(obj.Name) } else { http.Error(w, obj.Name+" not found", http.StatusBadRequest) return @@ -84,7 +84,7 @@ func (h Network) Delete(w http.ResponseWriter, r *http.Request) { http.Error(w, "network not found", http.StatusBadRequest) return } - h.Switcher.DelNetwork(network) + h.cs.DelNetwork(network) ResponseJson(w, "success") } @@ -94,7 +94,7 @@ func (h Network) Save(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - h.Switcher.SaveNetwork(network.Name) + h.cs.SaveNetwork(network.Name) ResponseJson(w, "success") } @@ -109,7 +109,7 @@ func (h Network) Profile(w http.ResponseWriter, r *http.Request) { } } -func (h Network) RestartVPN(w http.ResponseWriter, r *http.Request) { +func (h Network) StartVPN(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] @@ -124,7 +124,7 @@ func (h Network) RestartVPN(w http.ResponseWriter, r *http.Request) { } type SNAT struct { - Switcher Switcher + cs SwitchApi } func (h SNAT) Router(router *mux.Router) { @@ -159,3 +159,76 @@ func (h SNAT) Delete(w http.ResponseWriter, r *http.Request) { ResponseJson(w, "success") } + +type DNAT struct { + cs SwitchApi +} + +func (h DNAT) Router(router *mux.Router) { + router.HandleFunc("/api/network/{id}/dnat", h.Get).Methods("GET") + router.HandleFunc("/api/network/{id}/dnat", h.Post).Methods("POST") + router.HandleFunc("/api/network/{id}/dnat", h.Delete).Methods("DELETE") +} + +func (h DNAT) Get(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["id"] + + caller := Call.GetWorker(name) + if caller == nil { + http.Error(w, name+" not found", http.StatusBadRequest) + return + } + + var items []schema.DNAT + caller.ListDnat(func(data schema.DNAT) { + items = append(items, data) + }) + ResponseJson(w, items) +} + +func (h DNAT) Post(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["id"] + + caller := Call.GetWorker(name) + if caller == nil { + http.Error(w, name+" not found", http.StatusBadRequest) + return + } + + value := schema.DNAT{} + if err := GetData(r, &value); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + if err := caller.AddDnat(value); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + ResponseJson(w, "success") +} + +func (h DNAT) Delete(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["id"] + + caller := Call.GetWorker(name) + if caller == nil { + http.Error(w, name+" not found", http.StatusBadRequest) + return + } + + value := schema.DNAT{} + if err := GetData(r, &value); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + if err := caller.DelDnat(value); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + ResponseJson(w, "success") +} diff --git a/pkg/api/output.go b/pkg/api/output.go index 7cc46c5..0b4494e 100755 --- a/pkg/api/output.go +++ b/pkg/api/output.go @@ -11,7 +11,7 @@ import ( ) type Output struct { - Switcher Switcher + cs SwitchApi } func (h Output) Router(router *mux.Router) { @@ -45,7 +45,7 @@ func (h Output) Post(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - cs := h.Switcher.Config() + cs := h.cs.Config() if cs.Network[name] == nil { http.Error(w, "network is nil", http.StatusBadRequest) return @@ -68,7 +68,7 @@ func (h Output) Delete(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - cs := h.Switcher.Config() + cs := h.cs.Config() if cs.Network[name] == nil { http.Error(w, "network is nil", http.StatusBadRequest) return diff --git a/pkg/api/qos.go b/pkg/api/qos.go index 6cb271d..813551c 100644 --- a/pkg/api/qos.go +++ b/pkg/api/qos.go @@ -7,17 +7,17 @@ import ( "github.com/luscis/openlan/pkg/schema" ) -type QosApi struct { +type Qos struct { } -func (h QosApi) Router(router *mux.Router) { +func (h Qos) Router(router *mux.Router) { router.HandleFunc("/api/network/{id}/qos", h.List).Methods("GET") router.HandleFunc("/api/network/{id}/qos", h.Add).Methods("POST") router.HandleFunc("/api/network/{id}/qos", h.Del).Methods("DELETE") router.HandleFunc("/api/network/{id}/qos", h.Save).Methods("PUT") } -func (h QosApi) List(w http.ResponseWriter, r *http.Request) { +func (h Qos) List(w http.ResponseWriter, r *http.Request) { qosList := make([]schema.Qos, 0, 1024) vars := mux.Vars(r) @@ -37,7 +37,7 @@ func (h QosApi) List(w http.ResponseWriter, r *http.Request) { ResponseJson(w, qosList) } -func (h QosApi) Add(w http.ResponseWriter, r *http.Request) { +func (h Qos) Add(w http.ResponseWriter, r *http.Request) { qos := &schema.Qos{} if err := GetData(r, qos); err != nil { @@ -65,7 +65,7 @@ func (h QosApi) Add(w http.ResponseWriter, r *http.Request) { } } -func (h QosApi) Del(w http.ResponseWriter, r *http.Request) { +func (h Qos) Del(w http.ResponseWriter, r *http.Request) { qos := &schema.Qos{} if err := GetData(r, qos); err != nil { @@ -93,7 +93,7 @@ func (h QosApi) Del(w http.ResponseWriter, r *http.Request) { } } -func (h QosApi) Save(w http.ResponseWriter, r *http.Request) { +func (h Qos) Save(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] diff --git a/pkg/api/rate.go b/pkg/api/rate.go index 16f6ce8..bd122fa 100755 --- a/pkg/api/rate.go +++ b/pkg/api/rate.go @@ -8,7 +8,7 @@ import ( ) type Rate struct { - Switcher Switcher + cs SwitchApi } func (h Rate) Router(router *mux.Router) { @@ -25,11 +25,11 @@ func (h Rate) Post(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - h.Switcher.AddRate(device, rate.Speed) + h.cs.AddRate(device, rate.Speed) } func (h Rate) Delete(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) device := vars["id"] - h.Switcher.DelRate(device) + h.cs.DelRate(device) } diff --git a/pkg/api/route.go b/pkg/api/route.go index 72e7909..a1f1981 100644 --- a/pkg/api/route.go +++ b/pkg/api/route.go @@ -8,7 +8,7 @@ import ( ) type Route struct { - Switcher Switcher + cs SwitchApi } func (rt Route) Router(router *mux.Router) { @@ -52,7 +52,7 @@ func (rt Route) Add(w http.ResponseWriter, r *http.Request) { return } - if err := worker.AddRoute(pr, rt.Switcher); err != nil { + if err := worker.AddRoute(pr, rt.cs); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -76,7 +76,7 @@ func (rt Route) Del(w http.ResponseWriter, r *http.Request) { return } - if err := worker.DelRoute(pr, rt.Switcher); err != nil { + if err := worker.DelRoute(pr, rt.cs); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } diff --git a/pkg/api/server.go b/pkg/api/server.go index 1a6f3a0..40f4184 100755 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -1,12 +1,13 @@ package api import ( - "github.com/gorilla/mux" "net/http" + + "github.com/gorilla/mux" ) type Server struct { - Switcher Switcher + cs SwitchApi } func (l Server) Router(router *mux.Router) { @@ -15,14 +16,14 @@ func (l Server) Router(router *mux.Router) { } func (l Server) List(w http.ResponseWriter, r *http.Request) { - server := l.Switcher.Server() + server := l.cs.Server() data := &struct { UpTime int64 `json:"uptime"` Total int `json:"total"` Statistic map[string]int64 `json:"statistic"` Connection []interface{} `json:"connection"` }{ - UpTime: l.Switcher.UpTime(), + UpTime: l.cs.UpTime(), Statistic: server.Statistics(), Connection: make([]interface{}, 0, 1024), Total: server.TotalClient(), diff --git a/pkg/api/url.go b/pkg/api/url.go index b8abff3..2e81d09 100755 --- a/pkg/api/url.go +++ b/pkg/api/url.go @@ -2,8 +2,8 @@ package api import "github.com/gorilla/mux" -func Add(router *mux.Router, switcher Switcher) { - Link{Switcher: switcher}.Router(router) +func Add(router *mux.Router, cs SwitchApi) { + Link{cs: cs}.Router(router) User{}.Router(router) Bgp{}.Router(router) IPSec{}.Router(router) @@ -12,21 +12,22 @@ func Add(router *mux.Router, switcher Switcher) { Access{}.Router(router) OnLine{}.Router(router) Lease{}.Router(router) - Server{Switcher: switcher}.Router(router) + Server{cs: cs}.Router(router) Device{}.Router(router) VPNClient{}.Router(router) PProf{}.Router(router) - Config{Switcher: switcher}.Router(router) + Config{cs: cs}.Router(router) Version{}.Router(router) Log{}.Router(router) OpenAPI{}.Router(router) ZTrust{}.Router(router) - QosApi{}.Router(router) - Output{Switcher: switcher}.Router(router) + Qos{}.Router(router) + Output{cs: cs}.Router(router) ACL{}.Router(router) - Route{Switcher: switcher}.Router(router) + Route{cs: cs}.Router(router) FindHop{}.Router(router) - Rate{Switcher: switcher}.Router(router) + Rate{cs: cs}.Router(router) SNAT{}.Router(router) - Network{Switcher: switcher}.Router(router) + DNAT{}.Router(router) + Network{cs: cs}.Router(router) } diff --git a/pkg/api/ztrust.go b/pkg/api/ztrust.go index 5e3c2b6..d1fc092 100755 --- a/pkg/api/ztrust.go +++ b/pkg/api/ztrust.go @@ -11,7 +11,7 @@ import ( ) type ZTrust struct { - Switcher Switcher + cs SwitchApi } func (h ZTrust) Router(router *mux.Router) { diff --git a/pkg/config/network.go b/pkg/config/network.go index c3702d5..44f3e0b 100755 --- a/pkg/config/network.go +++ b/pkg/config/network.go @@ -180,12 +180,16 @@ func (n *Network) LoadDnat() { func (n *Network) Save() { obj := *n + obj.Routes = nil obj.Links = nil obj.Outputs = nil + obj.Dnat = nil + obj.FindHop = nil if err := libol.MarshalSave(&obj, obj.File, true); err != nil { libol.Error("Network.Save %s %s", obj.Name, err) } + n.SaveRoute() n.SaveLink() n.SaveOutput() @@ -341,3 +345,9 @@ func (n *Network) DelDnat(value *Dnat) (*Dnat, bool) { } return older, false } + +func (n *Network) ListDnat(call func(value Dnat)) { + for _, obj := range n.Dnat { + call(*obj) + } +} diff --git a/pkg/switch/bgp_linux.go b/pkg/switch/bgp_linux.go index fc770df..1f125f4 100644 --- a/pkg/switch/bgp_linux.go +++ b/pkg/switch/bgp_linux.go @@ -116,7 +116,7 @@ func (w *BgpWorker) reload() { } } -func (w *BgpWorker) Start(v api.Switcher) { +func (w *BgpWorker) Start(v api.SwitchApi) { w.uuid = v.UUID() w.out.Info("BgpWorker.Start") w.reload() @@ -172,7 +172,7 @@ func (w *BgpWorker) Get() *schema.Bgp { return data } -func (w *BgpWorker) Reload(v api.Switcher) { +func (w *BgpWorker) Reload(v api.SwitchApi) { w.Stop() w.Initialize() w.Start(v) diff --git a/pkg/switch/http.go b/pkg/switch/http.go index 7d5f9d8..6cc164c 100755 --- a/pkg/switch/http.go +++ b/pkg/switch/http.go @@ -31,7 +31,7 @@ func NotAllowed(w http.ResponseWriter, r *http.Request) { } type Http struct { - switcher api.Switcher + cs api.SwitchApi listen string adminToken string adminFile string @@ -42,10 +42,10 @@ type Http struct { router *mux.Router } -func NewHttp(switcher api.Switcher) (h *Http) { +func NewHttp(cs api.SwitchApi) (h *Http) { c := co.Get() h = &Http{ - switcher: switcher, + cs: cs, listen: c.Http.Listen, adminFile: c.TokenFile, pubDir: c.Http.Public, @@ -136,7 +136,7 @@ func (h *Http) LoadRouter() { h.Prome(router) 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.cs) } func (h *Http) LoadToken() { @@ -244,7 +244,7 @@ func (h *Http) PubFile(w http.ResponseWriter, r *http.Request) { func (h *Http) getIndex(body *schema.Index) *schema.Index { body.Version = schema.NewVersionSchema() - body.Worker = api.NewWorkerSchema(h.switcher) + body.Worker = api.NewWorkerSchema(h.cs) // display accessed Access. for p := range cache.Access.List() { diff --git a/pkg/switch/ipsec_linux.go b/pkg/switch/ipsec_linux.go index 7c8fdbb..a0ee371 100644 --- a/pkg/switch/ipsec_linux.go +++ b/pkg/switch/ipsec_linux.go @@ -184,7 +184,7 @@ func (w *IPSecWorker) addTunnel(tun *co.IPSecTunnel) error { return nil } -func (w *IPSecWorker) Start(v api.Switcher) { +func (w *IPSecWorker) Start(v api.SwitchApi) { w.uuid = v.UUID() w.out.Info("IPSecWorker.Start") for _, tun := range w.spec.Tunnels { @@ -261,7 +261,7 @@ func (w *IPSecWorker) Stop() { } } -func (w *IPSecWorker) Reload(v api.Switcher) { +func (w *IPSecWorker) Reload(v api.SwitchApi) { w.Stop() w.Initialize() w.Start(v) diff --git a/pkg/switch/network_linux.go b/pkg/switch/network_linux.go index cb42fe0..3fac68c 100755 --- a/pkg/switch/network_linux.go +++ b/pkg/switch/network_linux.go @@ -9,6 +9,7 @@ import ( "github.com/luscis/openlan/pkg/api" "github.com/luscis/openlan/pkg/cache" + "github.com/luscis/openlan/pkg/config" co "github.com/luscis/openlan/pkg/config" "github.com/luscis/openlan/pkg/libol" "github.com/luscis/openlan/pkg/models" @@ -17,8 +18,9 @@ import ( nl "github.com/vishvananda/netlink" ) -func NewNetworker(c *co.Network) api.Networker { - var obj api.Networker +func NewNetworker(c *co.Network) api.NetworkApi { + var obj api.NetworkApi + switch c.Provider { case "ipsec": secer := NewIPSecWorker(c) @@ -62,6 +64,7 @@ type WorkerImpl struct { acl *ACL findhop *FindHop snat *cn.FireWallChain + dnat *cn.FireWallChain } func NewWorkerApi(c *co.Network) *WorkerImpl { @@ -107,6 +110,7 @@ func (w *WorkerImpl) Initialize() { w.fire = cn.NewFireWallTable(cfg.Name) w.snat = cn.NewFireWallChain("XTT_"+cfg.Name+"_SNAT", cn.TNat, "") + w.dnat = cn.NewFireWallChain("XTT_"+cfg.Name+"_DNAT", cn.TNat, "") w.setV.Clear() w.setR.Clear() @@ -342,7 +346,7 @@ func (w *WorkerImpl) loadVRF() { } } -func (w *WorkerImpl) setMss() { +func (w *WorkerImpl) doMss() { cfg, _ := w.GetCfgs() mss := cfg.Bridge.Mss @@ -382,18 +386,20 @@ func (w *WorkerImpl) SetMss(mss int) { cfg, _ := w.GetCfgs() if cfg.Bridge.Mss != mss { cfg.Bridge.Mss = mss - w.setMss() + w.doMss() } } -func (w *WorkerImpl) enableSnat() { +func (w *WorkerImpl) doSnat() { + w.out.Info("WorkerImpl: doSnat") w.fire.Nat.Post.AddRuleX(cn.IPRule{ Jump: w.snat.Chain().Name, Comment: "Goto SNAT", }) } -func (w *WorkerImpl) disableSnat() { +func (w *WorkerImpl) undoSnat() { + w.out.Info("WorkerImpl: undoSnat") w.fire.Nat.Post.DelRuleX(cn.IPRule{ Jump: w.snat.Chain().Name, Comment: "Goto SNAT", @@ -404,7 +410,7 @@ func (w *WorkerImpl) EnableSnat() { cfg, _ := w.GetCfgs() if cfg.Snat == "disable" { cfg.Snat = "enable" - w.enableSnat() + w.doSnat() } } @@ -412,10 +418,97 @@ func (w *WorkerImpl) DisableSnat() { cfg, _ := w.GetCfgs() if cfg.Snat != "disable" { cfg.Snat = "disable" - w.disableSnat() + w.undoSnat() } } +func (w *WorkerImpl) doDnat() { + cfg, _ := w.GetCfgs() + w.out.Info("WorkerImpl: doDnat") + + w.fire.Nat.Pre.AddRuleX(cn.IPRule{ + Jump: w.dnat.Chain().Name, + Comment: "Goto DNAT", + }) + for _, obj := range cfg.Dnat { + if err := w.dnat.AddRuleX(cn.IPRule{ + Proto: obj.Protocol, + Dest: obj.Dest, + DstPort: fmt.Sprintf("%d", obj.Dport), + ToDest: fmt.Sprintf("%s:%d", obj.ToDest, obj.ToDport), + Jump: "DNAT", + Comment: "DNAT " + obj.Id(), + }); err != nil { + w.out.Warn("WorkerImple: doDnat: %s", err) + } + } +} + +func (w *WorkerImpl) AddDnat(data schema.DNAT) error { + cfg, _ := w.GetCfgs() + obj := config.Dnat{ + Protocol: data.Protocol, + Dest: data.Dest, + Dport: data.Dport, + ToDest: data.ToDest, + ToDport: data.ToDport, + } + obj.Correct() + + if ok := cfg.AddDnat(&obj); ok { + if err := w.dnat.AddRuleX(cn.IPRule{ + Proto: obj.Protocol, + Dest: obj.Dest, + DstPort: fmt.Sprintf("%d", obj.Dport), + ToDest: fmt.Sprintf("%s:%d", obj.ToDest, obj.ToDport), + Jump: "DNAT", + Comment: "DNAT " + obj.Id(), + }); err != nil { + w.out.Warn("WorkerImple: AddDnat: %s", err) + } + } + return nil +} + +func (w *WorkerImpl) DelDnat(data schema.DNAT) error { + cfg, _ := w.GetCfgs() + obj := config.Dnat{ + Protocol: data.Protocol, + Dest: data.Dest, + Dport: data.Dport, + ToDest: data.ToDest, + ToDport: data.ToDport, + } + obj.Correct() + + if _, ok := cfg.DelDnat(&obj); ok { + if err := w.dnat.DelRuleX(cn.IPRule{ + Proto: obj.Protocol, + Dest: obj.Dest, + DstPort: fmt.Sprintf("%d", obj.Dport), + ToDest: fmt.Sprintf("%s:%d", obj.ToDest, obj.ToDport), + Jump: "DNAT", + Comment: "DNAT " + obj.Id(), + }); err != nil { + w.out.Warn("WorkerImple: DelDnat: %s", err) + } + } + return nil +} + +func (w *WorkerImpl) ListDnat(call func(data schema.DNAT)) { + cfg, _ := w.GetCfgs() + cfg.ListDnat(func(value config.Dnat) { + call(schema.DNAT{ + Protocol: value.Protocol, + Dest: value.Dest, + Dport: value.Dport, + ToDest: value.ToDest, + ToDport: value.ToDport, + }) + }) +} + func (w *WorkerImpl) doTrust() { _, vpn := w.GetCfgs() w.fire.Mangle.Pre.AddRuleX(cn.IPRule{ @@ -425,7 +518,7 @@ func (w *WorkerImpl) doTrust() { }) } -func (w *WorkerImpl) disableTrust() { +func (w *WorkerImpl) undoTrust() { _, vpn := w.GetCfgs() w.fire.Mangle.Pre.DelRuleX(cn.IPRule{ Input: vpn.Device, @@ -446,7 +539,7 @@ func (w *WorkerImpl) DisableZTrust() { cfg, _ := w.GetCfgs() if cfg.ZTrust == "enable" { cfg.ZTrust = "disable" - w.disableTrust() + w.undoTrust() } } @@ -482,7 +575,7 @@ func (w *WorkerImpl) setVPN2VRF() { }) } -func (w *WorkerImpl) Start(v api.Switcher) { +func (w *WorkerImpl) Start(v api.SwitchApi) { cfg, vpn := w.GetCfgs() w.out.Info("WorkerImpl.Start") @@ -514,12 +607,15 @@ func (w *WorkerImpl) Start(v api.Switcher) { w.fire.Start() w.snat.Install() + w.dnat.Install() + + w.doDnat() if cfg.Snat != "disable" { - w.enableSnat() + w.doSnat() } if cfg.Bridge.Mss > 0 { // forward to remote - w.setMss() + w.doMss() } w.findhop.Start() @@ -636,10 +732,11 @@ func (w *WorkerImpl) Stop() { cfg, _ := w.GetCfgs() if cfg.Snat != "disable" { - w.disableSnat() + w.undoSnat() } w.snat.Cancel() + w.dnat.Cancel() w.fire.Stop() w.findhop.Stop() w.acl.Stop() @@ -707,7 +804,7 @@ func (w *WorkerImpl) Subnet() *net.IPNet { return nil } -func (w *WorkerImpl) Reload(v api.Switcher) { +func (w *WorkerImpl) Reload(v api.SwitchApi) { } func (w *WorkerImpl) toACL(input string) { @@ -1069,7 +1166,7 @@ func (w *WorkerImpl) ListRoute(call func(obj schema.PrefixRoute)) { }) } -func (w *WorkerImpl) AddRoute(route *schema.PrefixRoute, switcher api.Switcher) error { +func (w *WorkerImpl) AddRoute(route *schema.PrefixRoute, v api.SwitchApi) error { rt := w.correctRoute(route) if !w.cfg.AddRoute(rt) { w.out.Info("WorkerImpl.AddRoute: %s route exist", route.Prefix) @@ -1086,7 +1183,7 @@ func (w *WorkerImpl) AddRoute(route *schema.PrefixRoute, switcher api.Switcher) return nil } -func (w *WorkerImpl) DelRoute(route *schema.PrefixRoute, switcher api.Switcher) error { +func (w *WorkerImpl) DelRoute(route *schema.PrefixRoute, v api.SwitchApi) error { correctRt := w.correctRoute(route) delRt, removed := w.cfg.DelRoute(correctRt) if !removed { @@ -1107,7 +1204,7 @@ func (w *WorkerImpl) SaveRoute() { w.cfg.SaveRoute() } -func (w *WorkerImpl) Router() api.Router { +func (w *WorkerImpl) Router() api.RouteApi { return w } @@ -1146,18 +1243,19 @@ func (w *WorkerImpl) DelOutput(data schema.Output) { func (w *WorkerImpl) SaveOutput() { w.cfg.SaveOutput() } -func (w *WorkerImpl) ZTruster() api.ZTruster { + +func (w *WorkerImpl) ZTruster() api.ZTrustApi { return w.ztrust } -func (w *WorkerImpl) Qoser() api.Qoser { +func (w *WorkerImpl) Qoser() api.QosApi { return w.qos } -func (w *WorkerImpl) ACLer() api.ACLer { +func (w *WorkerImpl) ACLer() api.ACLApi { return w.acl } -func (w *WorkerImpl) FindHoper() api.FindHoper { +func (w *WorkerImpl) FindHoper() api.FindHopApi { return w.findhop } diff --git a/pkg/switch/openlan_linux.go b/pkg/switch/openlan_linux.go index 54c9145..c80d6c4 100755 --- a/pkg/switch/openlan_linux.go +++ b/pkg/switch/openlan_linux.go @@ -86,7 +86,7 @@ func (w *OpenLANWorker) UpBridge(cfg *co.Bridge) { } } -func (w *OpenLANWorker) Start(v api.Switcher) { +func (w *OpenLANWorker) Start(v api.SwitchApi) { w.uuid = v.UUID() w.startTime = time.Now().Unix() @@ -143,7 +143,7 @@ func (w *OpenLANWorker) DelLink(addr string) { } } -func (w *OpenLANWorker) Reload(v api.Switcher) { +func (w *OpenLANWorker) Reload(v api.SwitchApi) { w.Stop() w.Initialize() w.Start(v) diff --git a/pkg/switch/router_linux.go b/pkg/switch/router_linux.go index a68765a..ddfe12f 100755 --- a/pkg/switch/router_linux.go +++ b/pkg/switch/router_linux.go @@ -69,7 +69,7 @@ func (w *RouterWorker) addAddress() error { return nil } -func (w *RouterWorker) Start(v api.Switcher) { +func (w *RouterWorker) Start(v api.SwitchApi) { w.uuid = v.UUID() w.WorkerImpl.Start(v) w.addAddress() @@ -96,7 +96,7 @@ func (w *RouterWorker) Stop() { w.WorkerImpl.Stop() } -func (w *RouterWorker) Reload(v api.Switcher) { +func (w *RouterWorker) Reload(v api.SwitchApi) { w.Stop() w.Initialize() w.Start(v) diff --git a/pkg/switch/switch_linux.go b/pkg/switch/switch_linux.go index fc662c2..41df448 100755 --- a/pkg/switch/switch_linux.go +++ b/pkg/switch/switch_linux.go @@ -100,7 +100,7 @@ type Switch struct { hooks []Hook http *Http server libol.SocketServer - worker map[string]api.Networker + worker map[string]api.NetworkApi uuid string newTime int64 out *libol.SubLogger @@ -111,7 +111,7 @@ func NewSwitch(c *co.Switch) *Switch { v := &Switch{ cfg: c, fire: network.NewFireWallGlobal(c.FireWall), - worker: make(map[string]api.Networker, 32), + worker: make(map[string]api.NetworkApi, 32), server: server, newTime: time.Now().Unix(), hooks: make([]Hook, 0, 64),