From 418e1debe22308a46542528902093279adb2dcc1 Mon Sep 17 00:00:00 2001 From: Dario P Bazan Date: Tue, 7 May 2019 18:27:09 -0700 Subject: [PATCH 1/2] Adds support for port forwarding on non-nat network types --- cni/cni.go | 48 ++++++++++++++++++- network/policy.go | 47 ++++++++++-------- .../Microsoft/hcsshim/hcn/hcnpolicy.go | 1 + 3 files changed, 76 insertions(+), 20 deletions(-) diff --git a/cni/cni.go b/cni/cni.go index 1862eef4..ce1a5299 100644 --- a/cni/cni.go +++ b/cni/cni.go @@ -7,8 +7,10 @@ import ( "encoding/json" "fmt" "net" + "strconv" "strings" + "github.com/Microsoft/hcsshim/hcn" network "github.com/Microsoft/windows-container-networking/network" cniSkel "github.com/containernetworking/cni/pkg/skel" cniTypes "github.com/containernetworking/cni/pkg/types" @@ -68,6 +70,7 @@ type NetworkConfig struct { Type string `json:"type"` // As per SPEC, Type is Name of the Binary Ipam IpamConfig `json:"ipam"` DNS cniTypes.DNS `json:"dns"` + OptionalFlags OptionalFlags `json:"optionalFlags"` RuntimeConfig RuntimeConfig `json:"runtimeConfig"` AdditionalArgs []KVP } @@ -100,6 +103,11 @@ type K8SPodEnvArgs struct { K8S_POD_INFRA_CONTAINER_ID cniTypes.UnmarshallableString `json:"K8S_POD_INFRA_CONTAINER_ID,omitempty"` } +type OptionalFlags struct { + LocalRoutePortMapping bool `json:"localRoutedPortMapping"` + AllowAclPortMapping bool `json:"allowAclPortMapping"` +} + func (r *Result) Print() { fmt.Printf(r.String()) } @@ -269,13 +277,51 @@ func (config *NetworkConfig) GetEndpointInfo( runtimeConf := config.RuntimeConfig logrus.Debugf("Parsing port mappings from %+v", runtimeConf.PortMappings) + + flags := uint32(0) + if config.OptionalFlags.LocalRoutePortMapping { + flags = 1 + } + var aclPriority uint16 = 1000 for _, mapping := range runtimeConf.PortMappings { - policy, err := network.GetPortMappingPolicy(mapping.HostPort, mapping.ContainerPort, mapping.Protocol) + policy, err := network.GetPortMappingPolicy(mapping.HostPort, mapping.ContainerPort, mapping.Protocol, flags) if err != nil { return nil, fmt.Errorf("failed during GetEndpointInfo from netconf: %v", err) } logrus.Debugf("Created raw policy from mapping: %+v --- %+v", mapping, policy) epInfo.Policies = append(epInfo.Policies, policy) + + // Generate In ACLs for mapped ports + if config.OptionalFlags.AllowAclPortMapping { + in := hcn.AclPolicySetting{ + Protocols: mapping.Protocol, + Action: hcn.ActionTypeAllow, + Direction: hcn.DirectionTypeIn, + LocalPorts: strconv.Itoa(mapping.ContainerPort), + Priority: aclPriority, + } + + rawJSON, err := json.Marshal(in) + if err != nil { + return nil, fmt.Errorf("failed marshalling acl: %v", err) + } + + inPol := hcn.EndpointPolicy{ + Type: hcn.ACL, + Settings: rawJSON, + } + + rawData, err := json.Marshal(inPol) + inPolicy := network.Policy{ + Type: network.EndpointPolicy, + Data: rawData} + + if err != nil { + return nil, fmt.Errorf("failed marshalling acl: %v", err) + } + + epInfo.Policies = append(epInfo.Policies, inPolicy) + } } return epInfo, nil diff --git a/network/policy.go b/network/policy.go index 67c43e1c..f791dcff 100644 --- a/network/policy.go +++ b/network/policy.go @@ -7,6 +7,7 @@ import ( "encoding/json" "errors" "github.com/Microsoft/hcsshim/hcn" + "strconv" "strings" ) @@ -24,32 +25,40 @@ type Policy struct { } // GetPortMappingPolicy creates an HCN PortMappingPolicy and stores it in CNI Policy. -func GetPortMappingPolicy(externalPort int, internalPort int, protocol string) (Policy, error) { +func GetPortMappingPolicy(externalPort int, internalPort int, protocol string, flags uint32) (Policy, error) { var protocolInt uint32 - switch strings.ToLower(protocol) { - case "tcp": - protocolInt = 6 - break - case "udp": - protocolInt = 17 - break - case "icmpv4": - protocolInt = 1 - break - case "icmpv6": - protocolInt = 58 - break - case "igmp": - protocolInt = 2 - break - default: - return Policy{}, errors.New("invalid protocol supplied to port mapping policy") + + // protocol can be passed either as a number or a name + u, error := strconv.ParseUint(protocol, 0, 10) + if error != nil { + switch strings.ToLower(protocol) { + case "tcp": + protocolInt = 6 + break + case "udp": + protocolInt = 17 + break + case "icmpv4": + protocolInt = 1 + break + case "icmpv6": + protocolInt = 58 + break + case "igmp": + protocolInt = 2 + break + default: + return Policy{}, errors.New("invalid protocol supplied to port mapping policy") + } + } else { + protocolInt = uint32(u) } portMappingPolicy := hcn.PortMappingPolicySetting{ ExternalPort: uint16(externalPort), InternalPort: uint16(internalPort), Protocol: protocolInt, + Flags: flags, } rawPolicy, _ := json.Marshal(portMappingPolicy) endpointPolicy := hcn.EndpointPolicy{ diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnpolicy.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnpolicy.go index 6b12d73c..64969560 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnpolicy.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnpolicy.go @@ -72,6 +72,7 @@ type PortMappingPolicySetting struct { InternalPort uint16 `json:",omitempty"` ExternalPort uint16 `json:",omitempty"` VIP string `json:",omitempty"` + Flags uint32 `json:",omitempty"` } // ActionType associated with ACLs. Value is either Allow or Block. From 032bbff4c7f16bc8fcdc27bda6561dc035de7d4c Mon Sep 17 00:00:00 2001 From: Dario P Bazan Date: Wed, 8 May 2019 11:11:41 -0700 Subject: [PATCH 2/2] Moves the generate ACL code to its own function --- cni/cni.go | 65 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/cni/cni.go b/cni/cni.go index ce1a5299..3b2db1b7 100644 --- a/cni/cni.go +++ b/cni/cni.go @@ -251,6 +251,41 @@ func (config *NetworkConfig) GetNetworkInfo(podNamespace string) *network.Networ return ninfo } +// getInACLRule generates an In ACLs for mapped ports +func getInACLRule(mapping *PortMapping, aclPriority uint16) (*network.Policy, error) { + + var err error + + in := hcn.AclPolicySetting{ + Protocols: mapping.Protocol, + Action: hcn.ActionTypeAllow, + Direction: hcn.DirectionTypeIn, + LocalPorts: strconv.Itoa(mapping.ContainerPort), + Priority: aclPriority, + } + + rawJSON, err := json.Marshal(in) + if err != nil { + return nil, fmt.Errorf("failed marshalling acl: %v", err) + } + + inPol := hcn.EndpointPolicy{ + Type: hcn.ACL, + Settings: rawJSON, + } + + rawData, err := json.Marshal(inPol) + inPolicy := network.Policy{ + Type: network.EndpointPolicy, + Data: rawData} + + if err != nil { + return nil, fmt.Errorf("failed marshalling acl: %v", err) + } + + return &inPolicy, nil +} + // GetEndpointInfo constructs endpoint info using endpoint id, containerid and netns func (config *NetworkConfig) GetEndpointInfo( networkInfo *network.NetworkInfo, @@ -291,36 +326,12 @@ func (config *NetworkConfig) GetEndpointInfo( logrus.Debugf("Created raw policy from mapping: %+v --- %+v", mapping, policy) epInfo.Policies = append(epInfo.Policies, policy) - // Generate In ACLs for mapped ports if config.OptionalFlags.AllowAclPortMapping { - in := hcn.AclPolicySetting{ - Protocols: mapping.Protocol, - Action: hcn.ActionTypeAllow, - Direction: hcn.DirectionTypeIn, - LocalPorts: strconv.Itoa(mapping.ContainerPort), - Priority: aclPriority, - } - - rawJSON, err := json.Marshal(in) - if err != nil { - return nil, fmt.Errorf("failed marshalling acl: %v", err) - } - - inPol := hcn.EndpointPolicy{ - Type: hcn.ACL, - Settings: rawJSON, - } - - rawData, err := json.Marshal(inPol) - inPolicy := network.Policy{ - Type: network.EndpointPolicy, - Data: rawData} - + pol, err := getInACLRule(&mapping, aclPriority) if err != nil { - return nil, fmt.Errorf("failed marshalling acl: %v", err) + return nil, fmt.Errorf("failed getInACLRule: %v", err) } - - epInfo.Policies = append(epInfo.Policies, inPolicy) + epInfo.Policies = append(epInfo.Policies, *pol) } }