diff --git a/cmd/create/create_firewall.go b/cmd/create/create_firewall.go index ea28968..ad7e6a7 100644 --- a/cmd/create/create_firewall.go +++ b/cmd/create/create_firewall.go @@ -37,6 +37,7 @@ type CreateFirewallOptions struct { Drop bool Trap bool Record bool + Egress bool Mark uint32 } @@ -44,7 +45,7 @@ func NewCreateFirewallCmd(restOptions *api.RESTOptions) *cobra.Command { o := CreateFirewallOptions{} var createFirewallCmd = &cobra.Command{ - Use: "firewall --firewallRule=:, [--allow] [--drop] [--trap] [--record] [--redirect=] [--setmark=]", + Use: "firewall --firewallRule=:, [--allow] [--drop] [--trap] [--record] [--egress] [--redirect=] [--setmark=]", Short: "Create a Firewall", Long: `Create a Firewall using LoxiLB @@ -68,6 +69,7 @@ ex) loxicmd create firewall --firewallRule="sourceIP:1.2.3.2/32,destinationIP:2. loxicmd create firewall --firewallRule="sourceIP:1.2.3.2/32,destinationIP:2.3.1.2/32,preference:200" --redirect=hs1 loxicmd create firewall --firewallRule="sourceIP:1.2.3.2/32,destinationIP:2.3.1.2/32,preference:200" --snat=10.10.10.1,3030 loxicmd create firewall --firewallRule="sourceIP:1.2.3.2/32,destinationIP:2.3.1.2/32,preference:200" --snat=10.10.10.1 (Do not change sourceport) + loxicmd create firewall --firewallRule="sourceIP:1.2.3.2/32,destinationIP:2.3.1.2/32,preference:200" --snat=10.10.10.1,3030 --egress (Egress rules match for non-k8s traffic) `, Aliases: []string{"Firewall", "fw", "firewalls"}, PreRun: func(cmd *cobra.Command, args []string) { @@ -112,6 +114,7 @@ ex) loxicmd create firewall --firewallRule="sourceIP:1.2.3.2/32,destinationIP:2. createFirewallCmd.Flags().BoolVarP(&o.Trap, "trap", "", false, " Trap anything matching rule") createFirewallCmd.Flags().Uint32VarP(&o.Mark, "setmark", "", 0, " Add a fw mark") createFirewallCmd.Flags().StringSliceVar(&o.SnatArgs, "snat", o.SnatArgs, "SNAT any matching rule") + createFirewallCmd.Flags().BoolVarP(&o.Egress, "egress", "", false, "Specify that this an egress rule (to be used with snat)") createFirewallCmd.MarkFlagRequired("firewallRule") return createFirewallCmd } @@ -195,6 +198,7 @@ func GetFWOptionPairList(FirewallMods *api.FwRuleMod, o CreateFirewallOptions) e } else { FirewallMods.Opts.ToPort = 0 } + FirewallMods.Opts.OnDefault = o.Egress } FirewallMods.Opts.Record = o.Record FirewallMods.Opts.Mark = uint32(o.Mark) diff --git a/cmd/create/create_loadbalancer.go b/cmd/create/create_loadbalancer.go index 909d9d5..49127b7 100644 --- a/cmd/create/create_loadbalancer.go +++ b/cmd/create/create_loadbalancer.go @@ -53,6 +53,7 @@ type CreateLoadBalancerOptions struct { Host string AllowedSources []string PPv2En bool + Egress bool } type CreateLoadBalancerResult struct { @@ -140,7 +141,7 @@ func NewCreateLoadBalancerCmd(restOptions *api.RESTOptions) *cobra.Command { o := CreateLoadBalancerOptions{} var createLbCmd = &cobra.Command{ - Use: "lb IP [--select=] [--tcp=:] [--udp=:] [--sctp=:] [--icmp] [--mark=] [--secips=,] [--sources=,] [--endpoints=:,] [--mode=] [--bgp] [--monitor] [--inatimeout=] [--name=] [--attachEP] [--detachEP] [--security=] [--host=] [--ppv2en]", + Use: "lb IP [--select=] [--tcp=:] [--udp=:] [--sctp=:] [--icmp] [--mark=] [--secips=,] [--sources=,] [--endpoints=:,] [--mode=] [--bgp] [--monitor] [--inatimeout=] [--name=] [--attachEP] [--detachEP] [--security=] [--host=] [--ppv2en] [--egress]", Short: "Create a LoadBalancer", Long: `Create a LoadBalancer @@ -158,9 +159,10 @@ func NewCreateLoadBalancerCmd(restOptions *api.RESTOptions) *cobra.Command { hostonearm - LB operating in host one-arm ex) loxicmd create lb 192.168.0.200 --tcp=80:32015 --endpoints=10.212.0.1:1,10.212.0.2:1,10.212.0.3:1 - loxicmd create lb 192.168.0.200 --tcp=80:32015 --endpoints=10.212.0.1:1,10.212.0.2:1,10.212.0.3:1 --security=https + loxicmd create lb 192.168.0.200 --tcp=5000:5201-5300 --endpoints=10.212.0.1:1,10.212.0.2:1,10.212.0.3:1 + loxicmd create lb 192.168.0.200 --tcp=80:32015 --endpoints=10.212.0.1:1,10.212.0.2:1,10.212.0.3:1 --security=https loxicmd create lb 192.168.0.200 --tcp=80:32015 --endpoints=10.212.0.1:1,10.212.0.2:1,10.212.0.3:1 --host=loxilb.io - loxicmd create lb 192.168.0.200 --tcp=80:32015 --name="http-service" --endpoints=10.212.0.1:1,10.212.0.2:1,10.212.0.3:1 + loxicmd create lb 192.168.0.200 --tcp=80:32015 --name="http-service" --endpoints=10.212.0.1:1,10.212.0.2:1,10.212.0.3:1 loxicmd create lb 192.168.0.200 --udp=80:32015 --endpoints=10.212.0.1:1,10.212.0.2:1,10.212.0.3:1 --mark=10 loxicmd create lb 192.168.0.200 --tcp=80:32015 --udp=80:32015 --endpoints=10.212.0.1:1,10.212.0.2:1,10.212.0.3:1 loxicmd create lb 192.168.0.200 --select=hash --tcp=80:32015 --endpoints=10.212.0.1:1,10.212.0.2:1,10.212.0.3:1 @@ -215,12 +217,17 @@ ex) loxicmd create lb 192.168.0.200 --tcp=80:32015 --endpoints=10.212.0.1:1,10.2 return } for proto, portPairList := range ProtoPortpair { - portPair, err := GetPortPairList(portPairList) + portTargetPorts, err := GetPortPairList(portPairList) if err != nil { fmt.Printf("Error: %s\n", err.Error()) return } - for port, targetPort := range portPair { + if len(portTargetPorts) <= 0 { + fmt.Printf("portPair: None specified\n") + return + } + + for port := range portTargetPorts { lbModel := api.LoadBalancerModel{} oper := 0 if o.Attach { @@ -243,21 +250,24 @@ ex) loxicmd create lb 192.168.0.200 --tcp=80:32015 --endpoints=10.212.0.1:1,10.2 Security: api.LbSec(SecStringToNum(o.Security)), Host: o.Host, PpV2: o.PPv2En, - } - - if o.Mode == "dsr" && targetPort != port { - fmt.Printf("Error: No port-translation in dsr mode\n") - return + Egress: o.Egress, } lbModel.Service = lbService for endpoint, weight := range endpointPair { - ep := api.LoadBalancerEndpoint{ - EndpointIP: endpoint, - TargetPort: targetPort, - Weight: weight, + targetPorts := portTargetPorts[port] + for _, targetPort := range targetPorts { + if o.Mode == "dsr" && targetPort != port { + fmt.Printf("Error: No port-translation in dsr mode\n") + return + } + ep := api.LoadBalancerEndpoint{ + EndpointIP: endpoint, + TargetPort: targetPort, + Weight: weight, + } + lbModel.Endpoints = append(lbModel.Endpoints, ep) } - lbModel.Endpoints = append(lbModel.Endpoints, ep) } for _, sip := range o.SecIPs { @@ -289,7 +299,6 @@ ex) loxicmd create lb 192.168.0.200 --tcp=80:32015 --endpoints=10.212.0.1:1,10.2 } } } - }, } @@ -312,6 +321,7 @@ ex) loxicmd create lb 192.168.0.200 --tcp=80:32015 --endpoints=10.212.0.1:1,10.2 createLbCmd.Flags().StringVarP(&o.Host, "host", "", o.Host, "Ingress Host URL Path") createLbCmd.Flags().StringSliceVar(&o.AllowedSources, "sources", o.AllowedSources, "Allowed sources for this rule as ''") createLbCmd.Flags().BoolVarP(&o.PPv2En, "ppv2en", "", false, "Enable proxy procotol v2") + createLbCmd.Flags().BoolVarP(&o.Egress, "egress", "", false, "Specify egress rule") return createLbCmd } @@ -340,8 +350,8 @@ func PrintCreateResult(resp *http.Response, o api.RESTOptions) { fmt.Printf("%s\n", result.Result) } -func GetPortPairList(portPairStrList []string) (map[uint16]uint16, error) { - result := make(map[uint16]uint16) +func GetPortPairList(portPairStrList []string) (map[uint16][]uint16, error) { + result := make(map[uint16][]uint16) for _, portPairStr := range portPairStrList { portPair := strings.Split(portPairStr, ":") if len(portPair) != 2 { @@ -353,14 +363,38 @@ func GetPortPairList(portPairStrList []string) (map[uint16]uint16, error) { return nil, fmt.Errorf("port '%s' is not integer", portPair[0]) } - targetPort, err := strconv.Atoi(portPair[1]) - if err != nil { - return nil, fmt.Errorf("targetPort '%s' is not integer", portPair[1]) + startTP := 0 + endTP := 0 + + targetPortRange := strings.Split(portPair[1], "-") + if len(targetPortRange) > 2 { + continue + } else if len(targetPortRange) == 2 { + startTP, err = strconv.Atoi(targetPortRange[0]) + if err != nil { + return nil, fmt.Errorf("targetPort0 '%s' is not integer", targetPortRange[0]) + } + endTP, err = strconv.Atoi(targetPortRange[1]) + if err != nil { + return nil, fmt.Errorf("targetPort1 '%s' is not integer", targetPortRange[1]) + } + if endTP < startTP { + return nil, fmt.Errorf("targetPort2 '%s' < targetPort2 '%s'", targetPortRange[1], targetPortRange[0]) + } + } else { + startTP, err = strconv.Atoi(targetPortRange[0]) + if err != nil { + return nil, fmt.Errorf("targetPort0 '%s' is not integer", targetPortRange[0]) + } + endTP = startTP } - result[uint16(port)] = uint16(targetPort) - } + result[uint16(port)] = make([]uint16, 0) + for targetPort := startTP; targetPort <= endTP; targetPort++ { + result[uint16(port)] = append(result[uint16(port)], uint16(targetPort)) + } + } return result, nil } diff --git a/cmd/get/get_firewall.go b/cmd/get/get_firewall.go index 703abb1..0f771e9 100644 --- a/cmd/get/get_firewall.go +++ b/cmd/get/get_firewall.go @@ -115,11 +115,14 @@ func MakeFirewallOptionToString(t api.FwOptArg) (ret string) { ret = fmt.Sprintf("Snat(%s:%d)", t.ToIP, t.ToPort) } if t.Record { - ret += fmt.Sprintf(",Record") + ret += ",Record" } if t.Mark != 0 { ret += fmt.Sprintf(",FwMark(%v)", t.Mark) } + if t.OnDefault { + ret += ",Egr" + } return ret } diff --git a/cmd/get/get_loadbalancer.go b/cmd/get/get_loadbalancer.go index ed1c3e2..8a8d962 100644 --- a/cmd/get/get_loadbalancer.go +++ b/cmd/get/get_loadbalancer.go @@ -101,7 +101,7 @@ func NumToSecurty(sec int) string { return ret } -func NumToMode(mode int, ppv2 bool) string { +func NumToMode(mode int, ppv2 bool, egress bool) string { var ret string switch mode { case 1: @@ -120,6 +120,9 @@ func NumToMode(mode int, ppv2 bool) string { if ppv2 { ret += ":ppv2" } + if egress { + ret += ":egress" + } return ret } @@ -191,7 +194,7 @@ func PrintGetLbResult(resp *http.Response, o api.RESTOptions) { for i, eps := range lbrule.Endpoints { if i == 0 { - data = append(data, []string{lbrule.Service.ExternalIP, secIPs, sources, lbrule.Service.Host, fmt.Sprintf("%d", lbrule.Service.Port), protocolStr, lbrule.Service.Name, fmt.Sprintf("%d", lbrule.Service.Block), NumToSelect(int(lbrule.Service.Sel)), NumToMode(int(lbrule.Service.Mode), lbrule.Service.PpV2), + data = append(data, []string{lbrule.Service.ExternalIP, secIPs, sources, lbrule.Service.Host, fmt.Sprintf("%d", lbrule.Service.Port), protocolStr, lbrule.Service.Name, fmt.Sprintf("%d", lbrule.Service.Block), NumToSelect(int(lbrule.Service.Sel)), NumToMode(int(lbrule.Service.Mode), lbrule.Service.PpV2, lbrule.Service.Egress), eps.EndpointIP, fmt.Sprintf("%d", eps.TargetPort), fmt.Sprintf("%d", eps.Weight), eps.State, eps.Counter}) } else { data = append(data, []string{"", "", "", "", "", "", "", "", "", "", eps.EndpointIP, fmt.Sprintf("%d", eps.TargetPort), fmt.Sprintf("%d", eps.Weight), eps.State, eps.Counter}) @@ -200,7 +203,7 @@ func PrintGetLbResult(resp *http.Response, o api.RESTOptions) { } else { for i, eps := range lbrule.Endpoints { if i == 0 { - data = append(data, []string{lbrule.Service.ExternalIP, secIPs, sources, lbrule.Service.Host, fmt.Sprintf("%d", lbrule.Service.Port), protocolStr, lbrule.Service.Name, fmt.Sprintf("%d", lbrule.Service.Block), NumToSelect(int(lbrule.Service.Sel)), NumToMode(int(lbrule.Service.Mode), lbrule.Service.PpV2), + data = append(data, []string{lbrule.Service.ExternalIP, secIPs, sources, lbrule.Service.Host, fmt.Sprintf("%d", lbrule.Service.Port), protocolStr, lbrule.Service.Name, fmt.Sprintf("%d", lbrule.Service.Block), NumToSelect(int(lbrule.Service.Sel)), NumToMode(int(lbrule.Service.Mode), lbrule.Service.PpV2, lbrule.Service.Egress), eps.EndpointIP, fmt.Sprintf("%d", eps.TargetPort), fmt.Sprintf("%d", eps.Weight), "-", eps.Counter}) } else { data = append(data, []string{"", "", "", "", "", "", "", "", "", "", eps.EndpointIP, fmt.Sprintf("%d", eps.TargetPort), fmt.Sprintf("%d", eps.Weight), "-", eps.Counter}) @@ -209,7 +212,7 @@ func PrintGetLbResult(resp *http.Response, o api.RESTOptions) { } } else { table.SetHeader(LOADBALANCER_TITLE) - data = append(data, []string{lbrule.Service.ExternalIP, fmt.Sprintf("%d", lbrule.Service.Port), protocolStr, lbrule.Service.Name, fmt.Sprintf("%d", lbrule.Service.Block), NumToSelect(int(lbrule.Service.Sel)), NumToMode(int(lbrule.Service.Mode), lbrule.Service.PpV2), fmt.Sprintf("%d", len(lbrule.Endpoints)), BoolToMon(lbrule.Service.Monitor)}) + data = append(data, []string{lbrule.Service.ExternalIP, fmt.Sprintf("%d", lbrule.Service.Port), protocolStr, lbrule.Service.Name, fmt.Sprintf("%d", lbrule.Service.Block), NumToSelect(int(lbrule.Service.Sel)), NumToMode(int(lbrule.Service.Mode), lbrule.Service.PpV2, lbrule.Service.Egress), fmt.Sprintf("%d", len(lbrule.Endpoints)), BoolToMon(lbrule.Service.Monitor)}) } } diff --git a/pkg/api/firewall.go b/pkg/api/firewall.go index 1577fdb..96f2d31 100644 --- a/pkg/api/firewall.go +++ b/pkg/api/firewall.go @@ -46,6 +46,8 @@ type FwOptArg struct { DoSnat bool `json:"doSnat"` ToIP string `json:"toIP"` ToPort uint16 `json:"toPort"` + // OnDefault - Trigger only on default cases + OnDefault bool `json:"onDefault"` // Counter - Traffic counter Counter string `json:"counter"` } diff --git a/pkg/api/loadBalancer.go b/pkg/api/loadBalancer.go index eeb4f09..f9d543a 100644 --- a/pkg/api/loadBalancer.go +++ b/pkg/api/loadBalancer.go @@ -57,6 +57,7 @@ type LoadBalancerService struct { Security LbSec `json:"security,omitempty" yaml:"security"` Host string `json:"host,omitempty" yaml:"path"` PpV2 bool `json:"proxyprotocolv2" yaml:"proxyprotocolv2"` + Egress bool `json:"egress" yaml:"egress"` } type LoadBalancerEndpoint struct {