diff --git a/build/charts/antrea/crds/clusternetworkpolicy.yaml b/build/charts/antrea/crds/clusternetworkpolicy.yaml index 2f9ac6017c7..d2db9e7dee3 100644 --- a/build/charts/antrea/crds/clusternetworkpolicy.yaml +++ b/build/charts/antrea/crds/clusternetworkpolicy.yaml @@ -226,6 +226,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -472,6 +476,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: diff --git a/build/charts/antrea/crds/networkpolicy.yaml b/build/charts/antrea/crds/networkpolicy.yaml index 617100f054f..bdde3383665 100644 --- a/build/charts/antrea/crds/networkpolicy.yaml +++ b/build/charts/antrea/crds/networkpolicy.yaml @@ -162,6 +162,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -381,6 +385,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: diff --git a/build/yamls/antrea-aks.yml b/build/yamls/antrea-aks.yml index 540489e82c6..65f41822873 100644 --- a/build/yamls/antrea-aks.yml +++ b/build/yamls/antrea-aks.yml @@ -604,6 +604,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -850,6 +854,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1713,6 +1721,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1932,6 +1944,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: diff --git a/build/yamls/antrea-crds.yml b/build/yamls/antrea-crds.yml index 01a41d38565..fce283b5f39 100644 --- a/build/yamls/antrea-crds.yml +++ b/build/yamls/antrea-crds.yml @@ -597,6 +597,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -843,6 +847,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1694,6 +1702,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1913,6 +1925,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: diff --git a/build/yamls/antrea-eks.yml b/build/yamls/antrea-eks.yml index 3d2729d2530..e9f1e9d7e96 100644 --- a/build/yamls/antrea-eks.yml +++ b/build/yamls/antrea-eks.yml @@ -604,6 +604,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -850,6 +854,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1713,6 +1721,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1932,6 +1944,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: diff --git a/build/yamls/antrea-gke.yml b/build/yamls/antrea-gke.yml index 1a2800b9d58..8779172de50 100644 --- a/build/yamls/antrea-gke.yml +++ b/build/yamls/antrea-gke.yml @@ -604,6 +604,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -850,6 +854,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1713,6 +1721,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1932,6 +1944,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: diff --git a/build/yamls/antrea-ipsec.yml b/build/yamls/antrea-ipsec.yml index 505e6b54655..82881eb9ff7 100644 --- a/build/yamls/antrea-ipsec.yml +++ b/build/yamls/antrea-ipsec.yml @@ -604,6 +604,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -850,6 +854,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1713,6 +1721,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1932,6 +1944,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: diff --git a/build/yamls/antrea.yml b/build/yamls/antrea.yml index fbaccadcd05..29e22b3d8dc 100644 --- a/build/yamls/antrea.yml +++ b/build/yamls/antrea.yml @@ -604,6 +604,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -850,6 +854,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1713,6 +1721,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: @@ -1932,6 +1944,10 @@ spec: x-kubernetes-int-or-string: true endPort: type: integer + sourcePort: + type: integer + sourceEndPort: + type: integer protocols: type: array items: diff --git a/multicluster/build/yamls/antrea-multicluster-leader-global.yml b/multicluster/build/yamls/antrea-multicluster-leader-global.yml index 9e130736ccd..12ba3a6b31a 100644 --- a/multicluster/build/yamls/antrea-multicluster-leader-global.yml +++ b/multicluster/build/yamls/antrea-multicluster-leader-global.yml @@ -1114,8 +1114,8 @@ spec: properties: endPort: description: EndPort defines the end of the port range, - being the end included within the range. It can - only be specified when a numerical `port` is specified. + inclusive. It can only be specified when a numerical + `port` is specified. format: int32 type: integer port: @@ -1133,6 +1133,18 @@ spec: traffic must match. If not specified, this field defaults to TCP. type: string + sourceEndPort: + description: SourceEndPort defines the end of the + source port range, inclusive. It can only be specified + when `sourcePort` is specified. + format: int32 + type: integer + sourcePort: + description: The source port on the given protocol. + This can only be a numerical port. If this field + is not provided, rule matches all source ports. + format: int32 + type: integer type: object type: array protocols: @@ -2002,8 +2014,8 @@ spec: properties: endPort: description: EndPort defines the end of the port range, - being the end included within the range. It can - only be specified when a numerical `port` is specified. + inclusive. It can only be specified when a numerical + `port` is specified. format: int32 type: integer port: @@ -2021,6 +2033,18 @@ spec: traffic must match. If not specified, this field defaults to TCP. type: string + sourceEndPort: + description: SourceEndPort defines the end of the + source port range, inclusive. It can only be specified + when `sourcePort` is specified. + format: int32 + type: integer + sourcePort: + description: The source port on the given protocol. + This can only be a numerical port. If this field + is not provided, rule matches all source ports. + format: int32 + type: integer type: object type: array protocols: @@ -3814,8 +3838,8 @@ spec: properties: endPort: description: EndPort defines the end of the port range, - being the end included within the range. It can - only be specified when a numerical `port` is specified. + inclusive. It can only be specified when a numerical + `port` is specified. format: int32 type: integer port: @@ -3833,6 +3857,18 @@ spec: traffic must match. If not specified, this field defaults to TCP. type: string + sourceEndPort: + description: SourceEndPort defines the end of the + source port range, inclusive. It can only be specified + when `sourcePort` is specified. + format: int32 + type: integer + sourcePort: + description: The source port on the given protocol. + This can only be a numerical port. If this field + is not provided, rule matches all source ports. + format: int32 + type: integer type: object type: array protocols: @@ -4702,8 +4738,8 @@ spec: properties: endPort: description: EndPort defines the end of the port range, - being the end included within the range. It can - only be specified when a numerical `port` is specified. + inclusive. It can only be specified when a numerical + `port` is specified. format: int32 type: integer port: @@ -4721,6 +4757,18 @@ spec: traffic must match. If not specified, this field defaults to TCP. type: string + sourceEndPort: + description: SourceEndPort defines the end of the + source port range, inclusive. It can only be specified + when `sourcePort` is specified. + format: int32 + type: integer + sourcePort: + description: The source port on the given protocol. + This can only be a numerical port. If this field + is not provided, rule matches all source ports. + format: int32 + type: integer type: object type: array protocols: diff --git a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml index 67eb0134d15..66426e1647a 100644 --- a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml +++ b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml @@ -809,8 +809,8 @@ spec: properties: endPort: description: EndPort defines the end of the port range, - being the end included within the range. It can - only be specified when a numerical `port` is specified. + inclusive. It can only be specified when a numerical + `port` is specified. format: int32 type: integer port: @@ -828,6 +828,18 @@ spec: traffic must match. If not specified, this field defaults to TCP. type: string + sourceEndPort: + description: SourceEndPort defines the end of the + source port range, inclusive. It can only be specified + when `sourcePort` is specified. + format: int32 + type: integer + sourcePort: + description: The source port on the given protocol. + This can only be a numerical port. If this field + is not provided, rule matches all source ports. + format: int32 + type: integer type: object type: array protocols: @@ -1697,8 +1709,8 @@ spec: properties: endPort: description: EndPort defines the end of the port range, - being the end included within the range. It can - only be specified when a numerical `port` is specified. + inclusive. It can only be specified when a numerical + `port` is specified. format: int32 type: integer port: @@ -1716,6 +1728,18 @@ spec: traffic must match. If not specified, this field defaults to TCP. type: string + sourceEndPort: + description: SourceEndPort defines the end of the + source port range, inclusive. It can only be specified + when `sourcePort` is specified. + format: int32 + type: integer + sourcePort: + description: The source port on the given protocol. + This can only be a numerical port. If this field + is not provided, rule matches all source ports. + format: int32 + type: integer type: object type: array protocols: diff --git a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml index f95f24a776c..270ad6c6df4 100644 --- a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml +++ b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml @@ -807,8 +807,8 @@ spec: properties: endPort: description: EndPort defines the end of the port range, - being the end included within the range. It can - only be specified when a numerical `port` is specified. + inclusive. It can only be specified when a numerical + `port` is specified. format: int32 type: integer port: @@ -826,6 +826,18 @@ spec: traffic must match. If not specified, this field defaults to TCP. type: string + sourceEndPort: + description: SourceEndPort defines the end of the + source port range, inclusive. It can only be specified + when `sourcePort` is specified. + format: int32 + type: integer + sourcePort: + description: The source port on the given protocol. + This can only be a numerical port. If this field + is not provided, rule matches all source ports. + format: int32 + type: integer type: object type: array protocols: @@ -1695,8 +1707,8 @@ spec: properties: endPort: description: EndPort defines the end of the port range, - being the end included within the range. It can - only be specified when a numerical `port` is specified. + inclusive. It can only be specified when a numerical + `port` is specified. format: int32 type: integer port: @@ -1714,6 +1726,18 @@ spec: traffic must match. If not specified, this field defaults to TCP. type: string + sourceEndPort: + description: SourceEndPort defines the end of the + source port range, inclusive. It can only be specified + when `sourcePort` is specified. + format: int32 + type: integer + sourcePort: + description: The source port on the given protocol. + This can only be a numerical port. If this field + is not provided, rule matches all source ports. + format: int32 + type: integer type: object type: array protocols: diff --git a/pkg/agent/openflow/network_policy.go b/pkg/agent/openflow/network_policy.go index d7008370cae..c82ac9ab08e 100644 --- a/pkg/agent/openflow/network_policy.go +++ b/pkg/agent/openflow/network_policy.go @@ -60,6 +60,8 @@ var ( MatchUDPv6DstPort = types.NewMatchKey(binding.ProtocolUDPv6, types.L4PortAddr, "tp_dst") MatchSCTPDstPort = types.NewMatchKey(binding.ProtocolSCTP, types.L4PortAddr, "tp_dst") MatchSCTPv6DstPort = types.NewMatchKey(binding.ProtocolSCTPv6, types.L4PortAddr, "tp_dst") + MatchSCTPSrcPort = types.NewMatchKey(binding.ProtocolSCTP, types.L4PortAddr, "tp_src") + MatchSCTPv6SrcPort = types.NewMatchKey(binding.ProtocolSCTPv6, types.L4PortAddr, "tp_src") MatchTCPSrcPort = types.NewMatchKey(binding.ProtocolTCP, types.L4PortAddr, "tp_src") MatchTCPv6SrcPort = types.NewMatchKey(binding.ProtocolTCPv6, types.L4PortAddr, "tp_src") MatchUDPSrcPort = types.NewMatchKey(binding.ProtocolUDP, types.L4PortAddr, "tp_src") @@ -82,7 +84,7 @@ var ( protocolUDP = v1beta2.ProtocolUDP protocolTCP = v1beta2.ProtocolTCP - dnsPort = intstr.FromInt(53) + dnsPort = int32(53) ) type TCPFlags struct { @@ -706,19 +708,19 @@ func (c *client) NewDNSPacketInConjunction(id uint32) error { } udpService := v1beta2.Service{ Protocol: &protocolUDP, - Port: &dnsPort, + SrcPort: &dnsPort, } tcpService := v1beta2.Service{ Protocol: &protocolTCP, - Port: &dnsPort, + SrcPort: &dnsPort, } dnsPriority := priorityDNSIntercept conj.serviceClause = conj.newClause(1, 2, getTableByID(conj.ruleTableID), nil) conj.toClause = conj.newClause(2, 2, getTableByID(conj.ruleTableID), nil) c.featureNetworkPolicy.conjMatchFlowLock.Lock() defer c.featureNetworkPolicy.conjMatchFlowLock.Unlock() - ctxChanges := conj.serviceClause.addServiceFlows(c.featureNetworkPolicy, []v1beta2.Service{udpService}, &dnsPriority, true, false) - dnsTCPMatchPairs := getServiceMatchPairs(tcpService, c.featureNetworkPolicy.ipProtocols, true) + ctxChanges := conj.serviceClause.addServiceFlows(c.featureNetworkPolicy, []v1beta2.Service{udpService}, &dnsPriority, false) + dnsTCPMatchPairs := getServiceMatchPairs(tcpService, c.featureNetworkPolicy.ipProtocols) for _, dnsTCPMatchPair := range dnsTCPMatchPairs { tcpFlagsMatchPair := matchPair{ matchKey: MatchTCPFlags, @@ -846,9 +848,9 @@ func generateAddressConjMatch(ruleTableID uint8, addr types.Address, addrType ty return match } -func generateServiceConjMatches(ruleTableID uint8, service v1beta2.Service, priority *uint16, ipProtocols []binding.Protocol, matchSrc bool) []*conjunctiveMatch { +func generateServiceConjMatches(ruleTableID uint8, service v1beta2.Service, priority *uint16, ipProtocols []binding.Protocol) []*conjunctiveMatch { var matches []*conjunctiveMatch - conjMatchesMatchPairs := getServiceMatchPairs(service, ipProtocols, matchSrc) + conjMatchesMatchPairs := getServiceMatchPairs(service, ipProtocols) for _, conjMatchMatchPairs := range conjMatchesMatchPairs { matches = append(matches, &conjunctiveMatch{ @@ -860,57 +862,50 @@ func generateServiceConjMatches(ruleTableID uint8, service v1beta2.Service, prio return matches } -func getServiceMatchPairs(service v1beta2.Service, ipProtocols []binding.Protocol, matchSrc bool) [][]matchPair { +func getServiceMatchPairs(service v1beta2.Service, ipProtocols []binding.Protocol) [][]matchPair { var conjMatchesMatchPairs [][]matchPair - ovsBitRanges := serviceToBitRanges(service) - addL4MatchPairs := func(matchKey *types.MatchKey) { + ovsBitRanges := portsToBitRanges(service.Port, service.EndPort) + var srcOVSBitRanges []types.BitRange + if service.SrcPort != nil { + srcPortTyped := intstr.FromInt(int(*service.SrcPort)) + srcOVSBitRanges = portsToBitRanges(&srcPortTyped, service.SrcEndPort) + } + addL4MatchPairs := func(matchKey, srcMatchKey *types.MatchKey) { for _, ovsBitRange := range ovsBitRanges { - conjMatchesMatchPairs = append(conjMatchesMatchPairs, []matchPair{{matchKey: matchKey, matchValue: ovsBitRange}}) + matchPairs := []matchPair{{matchKey: matchKey, matchValue: ovsBitRange}} + if srcOVSBitRanges != nil { + for _, srcRange := range srcOVSBitRanges { + matchPairs = append(matchPairs, matchPair{matchKey: srcMatchKey, matchValue: srcRange}) + conjMatchesMatchPairs = append(conjMatchesMatchPairs, matchPairs) + } + } else { + conjMatchesMatchPairs = append(conjMatchesMatchPairs, matchPairs) + } } } switch *service.Protocol { case v1beta2.ProtocolTCP: - if !matchSrc { - for _, ipProtocol := range ipProtocols { - if ipProtocol == binding.ProtocolIP { - addL4MatchPairs(MatchTCPDstPort) - } else { - addL4MatchPairs(MatchTCPv6DstPort) - } - } - } else { - for _, ipProtocol := range ipProtocols { - if ipProtocol == binding.ProtocolIP { - addL4MatchPairs(MatchTCPSrcPort) - } else { - addL4MatchPairs(MatchTCPv6SrcPort) - } + for _, ipProtocol := range ipProtocols { + if ipProtocol == binding.ProtocolIP { + addL4MatchPairs(MatchTCPDstPort, MatchTCPSrcPort) + } else { + addL4MatchPairs(MatchTCPv6DstPort, MatchTCPv6SrcPort) } } case v1beta2.ProtocolUDP: - if !matchSrc { - for _, ipProtocol := range ipProtocols { - if ipProtocol == binding.ProtocolIP { - addL4MatchPairs(MatchUDPDstPort) - } else { - addL4MatchPairs(MatchUDPv6DstPort) - } - } - } else { - for _, ipProtocol := range ipProtocols { - if ipProtocol == binding.ProtocolIP { - addL4MatchPairs(MatchUDPSrcPort) - } else { - addL4MatchPairs(MatchUDPv6SrcPort) - } + for _, ipProtocol := range ipProtocols { + if ipProtocol == binding.ProtocolIP { + addL4MatchPairs(MatchUDPDstPort, MatchUDPSrcPort) + } else { + addL4MatchPairs(MatchUDPv6DstPort, MatchUDPv6SrcPort) } } case v1beta2.ProtocolSCTP: for _, ipProtocol := range ipProtocols { if ipProtocol == binding.ProtocolIP { - addL4MatchPairs(MatchSCTPDstPort) + addL4MatchPairs(MatchSCTPDstPort, MatchSCTPSrcPort) } else { - addL4MatchPairs(MatchSCTPv6DstPort) + addL4MatchPairs(MatchSCTPv6DstPort, MatchSCTPv6SrcPort) } } case v1beta2.ProtocolICMP: @@ -946,7 +941,7 @@ func getServiceMatchPairs(service v1beta2.Service, ipProtocols []binding.Protoco if service.IGMPType != nil && *service.IGMPType == crdv1alpha1.IGMPQuery { // Since OVS only matches layer 3 IP address on the IGMP query packet, and doesn't // identify the multicast group address set in the IGMP protocol, the flow entry - // processes all IGMP query packets by matching the destintaion IP address ( 224.0.0.1 ) + // processes all IGMP query packets by matching the destination IP address ( 224.0.0.1 ) if service.GroupAddress != "" { matchPairs = append(matchPairs, matchPair{matchKey: MatchDstIP, matchValue: net.ParseIP(service.GroupAddress)}) } else { @@ -956,18 +951,18 @@ func getServiceMatchPairs(service v1beta2.Service, ipProtocols []binding.Protoco conjMatchesMatchPairs = append(conjMatchesMatchPairs, matchPairs) } default: - addL4MatchPairs(MatchTCPDstPort) + addL4MatchPairs(MatchTCPDstPort, MatchTCPSrcPort) } return conjMatchesMatchPairs } -// serviceToBitRanges converts a Service to a list of BitRange. -func serviceToBitRanges(service v1beta2.Service) []types.BitRange { +// portsToBitRanges converts ports in Service to a list of BitRange. +func portsToBitRanges(port *intstr.IntOrString, endPort *int32) []types.BitRange { var ovsBitRanges []types.BitRange // If `EndPort` is equal to `Port`, then treat it as single port case. - if service.EndPort != nil && *service.EndPort > service.Port.IntVal { + if endPort != nil && *endPort > port.IntVal { // Add several antrea range services based on a port range. - portRange := thirdpartynp.PortRange{Start: uint16(service.Port.IntVal), End: uint16(*service.EndPort)} + portRange := thirdpartynp.PortRange{Start: uint16(port.IntVal), End: uint16(*endPort)} bitRanges, err := portRange.BitwiseMatch() if err != nil { klog.Errorf("Error when getting BitRanges from %v: %v", portRange, err) @@ -980,10 +975,10 @@ func serviceToBitRanges(service v1beta2.Service) []types.BitRange { Mask: &curBitRange.Mask, }) } - } else if service.Port != nil { + } else if port != nil { // Add single antrea service based on a single port. ovsBitRanges = append(ovsBitRanges, types.BitRange{ - Value: uint16(service.Port.IntVal), + Value: uint16(port.IntVal), }) } else { // Match all ports with the given protocol type if `Port` and `EndPort` are not @@ -1012,10 +1007,10 @@ func (c *clause) addAddrFlows(featureNetworkPolicy *featureNetworkPolicy, addrTy // addServiceFlows translates the specified Antrea Service to conjunctiveMatchFlow, // and returns corresponding conjMatchFlowContextChange. -func (c *clause) addServiceFlows(featureNetworkPolicy *featureNetworkPolicy, services []v1beta2.Service, priority *uint16, matchSrc bool, enableLogging bool) []*conjMatchFlowContextChange { +func (c *clause) addServiceFlows(featureNetworkPolicy *featureNetworkPolicy, services []v1beta2.Service, priority *uint16, enableLogging bool) []*conjMatchFlowContextChange { var conjMatchFlowContextChanges []*conjMatchFlowContextChange for _, service := range services { - matches := generateServiceConjMatches(c.ruleTable.GetID(), service, priority, featureNetworkPolicy.ipProtocols, matchSrc) + matches := generateServiceConjMatches(c.ruleTable.GetID(), service, priority, featureNetworkPolicy.ipProtocols) for _, match := range matches { ctxChange := c.addConjunctiveMatchFlow(featureNetworkPolicy, match, enableLogging, false) conjMatchFlowContextChanges = append(conjMatchFlowContextChanges, ctxChange) @@ -1230,7 +1225,7 @@ func (f *featureNetworkPolicy) addRuleToConjunctiveMatch(conj *policyRuleConjunc } if conj.serviceClause != nil { for _, eachService := range rule.Service { - matches := generateServiceConjMatches(conj.serviceClause.ruleTable.GetID(), eachService, rule.Priority, f.ipProtocols, false) + matches := generateServiceConjMatches(conj.serviceClause.ruleTable.GetID(), eachService, rule.Priority, f.ipProtocols) for _, match := range matches { f.addActionToConjunctiveMatch(conj.serviceClause, match, rule.EnableLogging, isMCNPRule) } @@ -1459,7 +1454,7 @@ func (c *policyRuleConjunction) calculateChangesForRuleCreation(featureNetworkPo ctxChanges = append(ctxChanges, c.toClause.addAddrFlows(featureNetworkPolicy, types.DstAddress, rule.To, rule.Priority, rule.EnableLogging, isMCNPRule)...) } if c.serviceClause != nil { - ctxChanges = append(ctxChanges, c.serviceClause.addServiceFlows(featureNetworkPolicy, rule.Service, rule.Priority, false, rule.EnableLogging)...) + ctxChanges = append(ctxChanges, c.serviceClause.addServiceFlows(featureNetworkPolicy, rule.Service, rule.Priority, rule.EnableLogging)...) } return ctxChanges } diff --git a/pkg/agent/openflow/network_policy_test.go b/pkg/agent/openflow/network_policy_test.go index 514c205dda7..e3ca34ec96e 100644 --- a/pkg/agent/openflow/network_policy_test.go +++ b/pkg/agent/openflow/network_policy_test.go @@ -65,6 +65,7 @@ var ( actionAllow = crdv1alpha1.RuleActionAllow actionDrop = crdv1alpha1.RuleActionDrop port8080 = intstr.FromInt(8080) + port32800 = int32(32800) protocolICMP = v1beta2.ProtocolICMP priority100 = uint16(100) priority200 = uint16(200) @@ -466,6 +467,22 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { UID: "id4", }, }, + { + Direction: v1beta2.DirectionIn, + From: parseAddresses([]string{"192.168.1.51"}), + Action: &actionDrop, + Priority: &priority100, + To: []types.Address{NewOFPortAddress(2)}, + Service: []v1beta2.Service{{Protocol: &protocolTCP, SrcPort: &port32800}}, + FlowID: uint32(14), + TableID: AntreaPolicyIngressRuleTable.GetID(), + PolicyRef: &v1beta2.NetworkPolicyReference{ + Type: v1beta2.AntreaNetworkPolicy, + Namespace: "ns1", + Name: "np5", + UID: "id5", + }, + }, }, expectedFlowsFn: func(c *client) []binding.Flow { cookiePolicy := c.cookieAllocator.Request(cookie.NetworkPolicy).Raw() @@ -489,6 +506,11 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { Action().LoadToRegField(APConjIDField, 13). Action().LoadRegMark(APDenyRegMark). Action().GotoTable(IngressMetricTable.GetID()).Done(), + AntreaPolicyIngressRuleTable.ofTable.BuildFlow(priority100).Cookie(cookiePolicy). + MatchConjID(14). + Action().LoadToRegField(APConjIDField, 14). + Action().LoadRegMark(APDenyRegMark). + Action().GotoTable(IngressMetricTable.GetID()).Done(), AntreaPolicyIngressRuleTable.ofTable.BuildFlow(priority100).Cookie(cookiePolicy). MatchProtocol(binding.ProtocolIP).MatchSrcIP(net.ParseIP("192.168.1.40")). Action().Conjunction(10, 1, 2). @@ -501,7 +523,8 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { Action().Conjunction(10, 1, 2).Done(), AntreaPolicyIngressRuleTable.ofTable.BuildFlow(priority100).Cookie(cookiePolicy). MatchProtocol(binding.ProtocolIP).MatchSrcIP(net.ParseIP("192.168.1.51")). - Action().Conjunction(11, 1, 3).Done(), + Action().Conjunction(11, 1, 3). + Action().Conjunction(14, 1, 3).Done(), AntreaPolicyIngressRuleTable.ofTable.BuildFlow(priority201).Cookie(cookiePolicy). MatchTunnelID(1). Action().Conjunction(13, 1, 3).Done(), @@ -517,7 +540,8 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { Action().Conjunction(12, 2, 3).Done(), AntreaPolicyIngressRuleTable.ofTable.BuildFlow(priority100).Cookie(cookiePolicy). MatchRegFieldWithValue(TargetOFPortField, uint32(2)). - Action().Conjunction(10, 2, 2).Done(), + Action().Conjunction(10, 2, 2). + Action().Conjunction(14, 2, 3).Done(), AntreaPolicyIngressRuleTable.ofTable.BuildFlow(priority100).Cookie(cookiePolicy). MatchRegFieldWithValue(TargetOFPortField, uint32(3)). Action().Conjunction(11, 2, 3).Done(), @@ -530,6 +554,9 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { AntreaPolicyIngressRuleTable.ofTable.BuildFlow(priority100).Cookie(cookiePolicy). MatchProtocol(binding.ProtocolTCP).MatchDstPort(8080, nil). Action().Conjunction(11, 3, 3).Done(), + AntreaPolicyIngressRuleTable.ofTable.BuildFlow(priority100).Cookie(cookiePolicy). + MatchProtocol(binding.ProtocolTCP).MatchSrcPort(32800, nil). + Action().Conjunction(14, 3, 3).Done(), AntreaPolicyIngressRuleTable.ofTable.BuildFlow(priority200).Cookie(cookiePolicy). MatchProtocol(binding.ProtocolTCP).MatchDstPort(8080, nil). Action().Conjunction(12, 3, 3).Done(), @@ -551,6 +578,9 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { IngressMetricTable.ofTable.BuildFlow(priorityNormal).Cookie(cookiePolicy). MatchRegMark(APDenyRegMark).MatchRegFieldWithValue(APConjIDField, 13). Action().Drop().Done(), + IngressMetricTable.ofTable.BuildFlow(priorityNormal).Cookie(cookiePolicy). + MatchRegMark(APDenyRegMark).MatchRegFieldWithValue(APConjIDField, 14). + Action().Drop().Done(), IngressDefaultTable.ofTable.BuildFlow(priority200).Cookie(cookiePolicy). MatchTunnelID(uint64(UnknownLabelIdentity)). MatchRegFieldWithValue(TargetOFPortField, uint32(1)). diff --git a/pkg/apis/controlplane/types.go b/pkg/apis/controlplane/types.go index 30cb6d6eb9c..86b7d5b6845 100644 --- a/pkg/apis/controlplane/types.go +++ b/pkg/apis/controlplane/types.go @@ -289,10 +289,16 @@ type Service struct { // and the Protocol is TCP, UDP, or SCTP, this matches all port numbers. // +optional Port *intstr.IntOrString - // EndPort defines the end of the port range, being the end included within the range. + // EndPort defines the end of the port range, inclusive. // It can only be specified when a numerical `port` is specified. // +optional EndPort *int32 + // SrcPort and SrcEndPort can only be specified, when the Protocol is TCP, UDP, or SCTP. + // It restricts the source port of the traffic. + // +optional + SrcPort *int32 + // +optional + SrcEndPort *int32 // ICMPType and ICMPCode can only be specified, when the Protocol is ICMP. If they // both are not specified and the Protocol is ICMP, this matches all ICMP traffic. ICMPType *int32 diff --git a/pkg/apis/controlplane/v1beta2/generated.pb.go b/pkg/apis/controlplane/v1beta2/generated.pb.go index c533055ea35..3661ec8f641 100644 --- a/pkg/apis/controlplane/v1beta2/generated.pb.go +++ b/pkg/apis/controlplane/v1beta2/generated.pb.go @@ -1273,179 +1273,182 @@ func init() { } var fileDescriptor_fbaa7d016762fa1d = []byte{ - // 2751 bytes of a gzipped FileDescriptorProto + // 2787 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3a, 0xcb, 0x6f, 0x24, 0x47, - 0xf9, 0xdb, 0xf3, 0xb0, 0x3d, 0x9f, 0x1f, 0xeb, 0x2d, 0x27, 0x59, 0xff, 0x92, 0xac, 0xbd, 0xe9, - 0xfc, 0x88, 0x16, 0x14, 0x66, 0x62, 0x93, 0x64, 0x97, 0xbc, 0xc0, 0xe3, 0xf5, 0x3a, 0x43, 0x6c, - 0x67, 0x52, 0x76, 0x14, 0x29, 0x21, 0x21, 0xed, 0xee, 0x9a, 0x99, 0x62, 0x7b, 0xba, 0x3a, 0xd5, - 0x35, 0xce, 0x3a, 0x07, 0x14, 0x14, 0x38, 0x84, 0x57, 0x10, 0x42, 0x42, 0xdc, 0xb8, 0x71, 0xe1, - 0x2f, 0xc8, 0x8d, 0x5b, 0x8e, 0x41, 0x08, 0x91, 0x93, 0x45, 0x8c, 0x08, 0xca, 0x01, 0x0e, 0xdc, - 0x58, 0x84, 0x84, 0xaa, 0xba, 0xfa, 0x39, 0x9e, 0xf5, 0x8e, 0xed, 0x35, 0x12, 0xc9, 0x69, 0xa6, - 0xbf, 0x77, 0x55, 0x7d, 0x5f, 0x7d, 0x8f, 0x6e, 0x78, 0xc6, 0xf2, 0x04, 0x27, 0x56, 0x95, 0xb2, - 0x5a, 0xf8, 0xaf, 0xe6, 0x5f, 0x6f, 0xd7, 0x2c, 0x9f, 0x06, 0x35, 0x9b, 0x79, 0x82, 0x33, 0xd7, - 0x77, 0x2d, 0x8f, 0xd4, 0x76, 0x16, 0xb6, 0x89, 0xb0, 0x16, 0x6b, 0x6d, 0xe2, 0x11, 0x6e, 0x09, - 0xe2, 0x54, 0x7d, 0xce, 0x04, 0x43, 0xd5, 0x90, 0xeb, 0x5b, 0x94, 0xe9, 0x7f, 0x55, 0xff, 0x7a, - 0xbb, 0x2a, 0xf9, 0xab, 0x69, 0xfe, 0xaa, 0xe6, 0xbf, 0xf7, 0xca, 0x60, 0x7d, 0x81, 0xb0, 0x44, - 0x50, 0xdb, 0x59, 0xb0, 0x5c, 0xbf, 0x63, 0x2d, 0xe4, 0x35, 0xdd, 0xfb, 0xe5, 0x36, 0x15, 0x9d, - 0xde, 0x76, 0xd5, 0x66, 0xdd, 0x5a, 0x9b, 0xb5, 0x59, 0x4d, 0x81, 0xb7, 0x7b, 0x2d, 0xf5, 0xa4, - 0x1e, 0xd4, 0x3f, 0x4d, 0xfe, 0xe8, 0xf5, 0x2b, 0x81, 0xd2, 0xe2, 0xd3, 0xae, 0x65, 0x77, 0xa8, - 0x47, 0xf8, 0x6e, 0xa2, 0xab, 0x4b, 0x84, 0x55, 0xdb, 0xe9, 0x57, 0x52, 0x1b, 0xc4, 0xc5, 0x7b, - 0x9e, 0xa0, 0x5d, 0xd2, 0xc7, 0xf0, 0xf8, 0x61, 0x0c, 0x81, 0xdd, 0x21, 0x5d, 0xab, 0x8f, 0xef, - 0x2b, 0x83, 0xf8, 0x7a, 0x82, 0xba, 0x35, 0xea, 0x89, 0x40, 0xf0, 0x3c, 0x93, 0xf9, 0x57, 0x03, - 0x26, 0x96, 0x1c, 0x87, 0x93, 0x20, 0x58, 0xe5, 0xac, 0xe7, 0xa3, 0xd7, 0x61, 0x4c, 0xae, 0xc4, - 0xb1, 0x84, 0x35, 0x6b, 0x5c, 0x34, 0x2e, 0x8d, 0x2f, 0x3e, 0x52, 0x0d, 0x05, 0x57, 0xd3, 0x82, - 0x93, 0x33, 0x91, 0xd4, 0xd5, 0x9d, 0x85, 0xea, 0xf3, 0xdb, 0xdf, 0x26, 0xb6, 0x58, 0x27, 0xc2, - 0xaa, 0xa3, 0x0f, 0xf6, 0xe6, 0xcf, 0xec, 0xef, 0xcd, 0x43, 0x02, 0xc3, 0xb1, 0x54, 0xd4, 0x83, - 0x89, 0xb6, 0x54, 0xb5, 0x4e, 0xba, 0xdb, 0x84, 0x07, 0xb3, 0x85, 0x8b, 0xc5, 0x4b, 0xe3, 0x8b, - 0x4f, 0x0e, 0x79, 0xec, 0xd5, 0xd5, 0x44, 0x46, 0xfd, 0x2e, 0xad, 0x70, 0x22, 0x05, 0x0c, 0x70, - 0x46, 0x8d, 0xf9, 0x7b, 0x03, 0xa6, 0xd3, 0x2b, 0x5d, 0xa3, 0x81, 0x40, 0xdf, 0xec, 0x5b, 0x6d, - 0xf5, 0xf6, 0x56, 0x2b, 0xb9, 0xd5, 0x5a, 0xa7, 0xb5, 0xea, 0xb1, 0x08, 0x92, 0x5a, 0xa9, 0x05, - 0x65, 0x2a, 0x48, 0x37, 0x5a, 0xe2, 0x53, 0xc3, 0x2e, 0x31, 0x6d, 0x6e, 0x7d, 0x52, 0x2b, 0x2a, - 0x37, 0xa4, 0x48, 0x1c, 0x4a, 0x36, 0xdf, 0x2d, 0xc2, 0xb9, 0x34, 0x59, 0xd3, 0x12, 0x76, 0xe7, - 0x14, 0x0e, 0xf1, 0x7b, 0x06, 0x9c, 0xb3, 0x1c, 0x87, 0x38, 0xab, 0x27, 0x7c, 0x94, 0xff, 0xa7, - 0xd5, 0xca, 0x55, 0x65, 0xa5, 0xe3, 0x7e, 0x85, 0xe8, 0x07, 0x06, 0xcc, 0x70, 0xd2, 0x65, 0x3b, - 0x39, 0x43, 0x8a, 0xc7, 0x37, 0xe4, 0x3e, 0x6d, 0xc8, 0x0c, 0xee, 0x97, 0x8f, 0x0f, 0x52, 0x6a, - 0x7e, 0x6a, 0xc0, 0xd4, 0x92, 0xef, 0xbb, 0x94, 0x38, 0x5b, 0xec, 0x7f, 0x3c, 0x9a, 0xfe, 0x68, - 0x00, 0xca, 0xae, 0xf5, 0x14, 0xe2, 0xc9, 0xce, 0xc6, 0xd3, 0x33, 0x43, 0xc7, 0x53, 0xc6, 0xe0, - 0x01, 0x11, 0xf5, 0xc3, 0x22, 0xcc, 0x64, 0x09, 0x3f, 0x8f, 0xa9, 0xff, 0x5e, 0x4c, 0xbd, 0x01, - 0x33, 0x75, 0x2b, 0xa0, 0xf6, 0x52, 0x4f, 0x74, 0x88, 0x27, 0xa8, 0x6d, 0x09, 0xca, 0x3c, 0xf4, - 0x30, 0x8c, 0xf5, 0x02, 0xc2, 0x3d, 0xab, 0x4b, 0xd4, 0x61, 0x54, 0x12, 0xbf, 0x79, 0x51, 0xc3, - 0x71, 0x4c, 0x21, 0xa9, 0x7d, 0x2b, 0x08, 0xde, 0x64, 0xdc, 0x99, 0x2d, 0x64, 0xa9, 0x9b, 0x1a, - 0x8e, 0x63, 0x0a, 0x73, 0x01, 0xa6, 0xeb, 0x3d, 0xcf, 0x71, 0xc9, 0x35, 0xea, 0x92, 0x4d, 0xc2, - 0x77, 0x08, 0x47, 0x17, 0xa0, 0xd8, 0xe3, 0xae, 0x56, 0x35, 0xae, 0x99, 0x8b, 0x2f, 0xe2, 0x35, - 0x2c, 0xe1, 0xe6, 0x7b, 0x05, 0xb8, 0x10, 0xf2, 0x84, 0xf4, 0xd2, 0xda, 0x65, 0xe6, 0xb5, 0x68, - 0xbb, 0xc7, 0x43, 0x83, 0x1f, 0x83, 0xf1, 0x6d, 0x62, 0x71, 0xc2, 0xb7, 0xd8, 0x75, 0xe2, 0x69, - 0x41, 0x33, 0x5a, 0xd0, 0x78, 0x3d, 0x41, 0xe1, 0x34, 0x1d, 0x7a, 0x08, 0x46, 0x2c, 0x9f, 0x3e, - 0x47, 0x76, 0xb5, 0xdd, 0x53, 0x9a, 0x63, 0x64, 0xa9, 0xd9, 0x78, 0x8e, 0xec, 0x62, 0x8d, 0x45, - 0x3f, 0x31, 0x60, 0x66, 0xbb, 0x7f, 0x9f, 0x66, 0x8b, 0xca, 0x51, 0x97, 0x87, 0x3d, 0xb3, 0x03, - 0xb6, 0xbc, 0x7e, 0x5e, 0x9e, 0xdb, 0x01, 0x08, 0x7c, 0x90, 0x62, 0xf3, 0x57, 0x25, 0x98, 0x59, - 0x76, 0x7b, 0x81, 0x20, 0x3c, 0xe3, 0x5c, 0x77, 0x3e, 0x8a, 0xbe, 0x6b, 0xc0, 0x34, 0x69, 0xb5, - 0x88, 0x2d, 0xe8, 0x0e, 0x39, 0xc1, 0x20, 0x9a, 0xd5, 0x5a, 0xa7, 0x57, 0x72, 0xc2, 0x71, 0x9f, - 0x3a, 0xf4, 0x1d, 0x38, 0x17, 0xc3, 0x1a, 0xcd, 0xba, 0xcb, 0xec, 0xeb, 0x51, 0xfc, 0x3c, 0x36, - 0xac, 0x0d, 0x8d, 0xe6, 0x06, 0x11, 0x49, 0x08, 0xaf, 0xe4, 0xe5, 0xe2, 0x7e, 0x55, 0xe8, 0x0a, - 0x4c, 0x08, 0x26, 0x2c, 0x37, 0x5a, 0x7e, 0xe9, 0xa2, 0x71, 0xa9, 0x98, 0xdc, 0xeb, 0x5b, 0x29, - 0x1c, 0xce, 0x50, 0xa2, 0x45, 0x00, 0xf5, 0xdc, 0xb4, 0xda, 0x24, 0x98, 0x2d, 0x2b, 0xbe, 0x78, - 0xbf, 0xb7, 0x62, 0x0c, 0x4e, 0x51, 0x49, 0xdf, 0xb6, 0x7b, 0x9c, 0x13, 0x4f, 0xc8, 0xe7, 0xd9, - 0x11, 0xc5, 0x14, 0xfb, 0xf6, 0x72, 0x82, 0xc2, 0x69, 0x3a, 0xf3, 0x13, 0x03, 0xc6, 0x57, 0xda, - 0x9f, 0x81, 0xca, 0xf3, 0x77, 0x06, 0x9c, 0x4d, 0x2d, 0xf4, 0x14, 0x12, 0xe5, 0xeb, 0xd9, 0x44, - 0x39, 0xf4, 0x0a, 0x53, 0xd6, 0x0e, 0xc8, 0x92, 0x3f, 0x2a, 0xc2, 0x74, 0x8a, 0x2a, 0x4c, 0x91, - 0x0e, 0x00, 0x8b, 0xf7, 0xfd, 0x44, 0xcf, 0x30, 0x25, 0xf7, 0xf3, 0x34, 0x79, 0x40, 0x9a, 0x74, - 0xe1, 0xfc, 0xca, 0x0d, 0x21, 0xd3, 0x9d, 0xbb, 0xe2, 0x09, 0x2a, 0x76, 0x31, 0x69, 0x11, 0x4e, - 0x3c, 0x9b, 0xa0, 0x8b, 0x50, 0x4a, 0xa5, 0xc9, 0x09, 0x2d, 0xba, 0xb4, 0x21, 0x53, 0xa4, 0xc2, - 0xa0, 0x1a, 0x54, 0xe4, 0x6f, 0xe0, 0x5b, 0x36, 0xd1, 0x79, 0xe6, 0x9c, 0x26, 0xab, 0x6c, 0x44, - 0x08, 0x9c, 0xd0, 0x98, 0xff, 0x32, 0x60, 0x5a, 0xa9, 0x5f, 0x0a, 0x02, 0x66, 0xd3, 0x30, 0xc3, - 0x9d, 0x4a, 0x7d, 0x34, 0x6d, 0x69, 0x8d, 0x7a, 0xfd, 0x47, 0x2e, 0x05, 0x15, 0x77, 0xbc, 0x49, - 0xc9, 0xe5, 0xbe, 0x94, 0x93, 0x8f, 0xfb, 0x34, 0x9a, 0xef, 0x97, 0x60, 0x3c, 0xb5, 0xf9, 0xe8, - 0x25, 0x28, 0xfa, 0xcc, 0xd1, 0x6b, 0x1e, 0xba, 0xc7, 0x6b, 0x32, 0x27, 0x31, 0x63, 0x54, 0x56, - 0x15, 0x12, 0x22, 0x25, 0xa2, 0x77, 0x0c, 0x98, 0x22, 0x99, 0x53, 0x55, 0xa7, 0x33, 0xbe, 0xb8, - 0x3a, 0x74, 0x3c, 0x1f, 0xec, 0x1b, 0x75, 0xb4, 0xbf, 0x37, 0x3f, 0x95, 0x43, 0xe6, 0x54, 0xa2, - 0x87, 0xa0, 0x48, 0xfd, 0xd0, 0xad, 0x27, 0xea, 0x77, 0x49, 0x03, 0x1b, 0xcd, 0xe0, 0xe6, 0xde, - 0x7c, 0xa5, 0xd1, 0xd4, 0x8d, 0x27, 0x96, 0x04, 0xe8, 0x35, 0x28, 0xfb, 0x8c, 0x0b, 0x99, 0x6c, - 0xe4, 0x89, 0x7c, 0x75, 0x58, 0x1b, 0xa5, 0xa7, 0x39, 0x4d, 0xc6, 0x45, 0x72, 0xe3, 0xc8, 0xa7, - 0x00, 0x87, 0x62, 0xd1, 0x2b, 0x50, 0xf2, 0x98, 0x43, 0x54, 0x4e, 0x1a, 0x5f, 0x7c, 0x7a, 0x68, - 0xf1, 0xcc, 0x21, 0xc9, 0xc2, 0xc7, 0x54, 0x08, 0x48, 0x90, 0x12, 0x8a, 0xda, 0x30, 0x1a, 0x10, - 0xbe, 0x43, 0xed, 0x30, 0x7d, 0x8d, 0x2f, 0x7e, 0x7d, 0x58, 0xf9, 0x9b, 0x21, 0x7b, 0xa2, 0x62, - 0x7c, 0x7f, 0x6f, 0x7e, 0x34, 0x82, 0x46, 0xd2, 0xcd, 0x5f, 0x1b, 0x30, 0x95, 0xf5, 0xbd, 0x6c, - 0xf8, 0x19, 0x87, 0x87, 0x5f, 0x1c, 0xd1, 0x85, 0x81, 0x11, 0x5d, 0x87, 0x62, 0x8f, 0x3a, 0xaa, - 0xfa, 0xab, 0xd4, 0x1f, 0x89, 0xcb, 0xd5, 0xc6, 0xd5, 0x9b, 0x7b, 0xf3, 0x0f, 0x0c, 0x1a, 0x13, - 0x89, 0x5d, 0x9f, 0x04, 0xd5, 0x17, 0x1b, 0x57, 0xb1, 0x64, 0x36, 0xdf, 0x82, 0x89, 0x67, 0xb7, - 0xb6, 0x9a, 0x4d, 0xce, 0x04, 0xb3, 0x99, 0x2b, 0xb5, 0x76, 0x58, 0x20, 0xf2, 0xf7, 0xc8, 0xb3, - 0x2c, 0x10, 0x58, 0x61, 0x64, 0xb1, 0xda, 0x25, 0xa2, 0xc3, 0x9c, 0x7c, 0xb1, 0xba, 0xae, 0xa0, - 0x58, 0x63, 0xa5, 0x24, 0xdf, 0x12, 0x1d, 0x6d, 0x5e, 0x2c, 0xa9, 0x69, 0x89, 0x0e, 0x56, 0x18, - 0xf3, 0xb7, 0x06, 0x8c, 0xea, 0x62, 0x06, 0xbd, 0x04, 0x25, 0x9b, 0x3a, 0x5c, 0xc7, 0xd7, 0x11, - 0xcb, 0xa7, 0x58, 0xc9, 0x72, 0xe3, 0x2a, 0xc6, 0x4a, 0x20, 0x7a, 0x15, 0x46, 0xc8, 0x0d, 0x9b, - 0xf8, 0x42, 0xdf, 0x21, 0x47, 0x14, 0x1d, 0xaf, 0x72, 0x45, 0x09, 0xc3, 0x5a, 0xa8, 0xf9, 0x6f, - 0x03, 0x50, 0xa3, 0xf9, 0xd9, 0xbd, 0x26, 0x5b, 0x50, 0x56, 0x1b, 0x84, 0x1e, 0x84, 0x02, 0xf5, - 0xd5, 0x5a, 0x27, 0xea, 0x33, 0xfb, 0x7b, 0xf3, 0x85, 0x46, 0x33, 0x7b, 0x7d, 0x14, 0xa8, 0x2f, - 0x2b, 0x56, 0x9f, 0x93, 0x16, 0xbd, 0xb1, 0x46, 0xbc, 0xb6, 0xe8, 0x28, 0x0f, 0x2a, 0x27, 0xd5, - 0x55, 0x33, 0x85, 0xc3, 0x19, 0x4a, 0xb3, 0x03, 0xb0, 0x76, 0x39, 0xf6, 0xd2, 0x97, 0xa1, 0xd4, - 0x11, 0xc2, 0x3f, 0xea, 0x6d, 0x9c, 0xf6, 0xf8, 0xf0, 0x92, 0x90, 0x10, 0xac, 0x64, 0x9a, 0xbf, - 0x34, 0x00, 0xad, 0xf7, 0x5c, 0xd9, 0xe3, 0x04, 0x42, 0xad, 0xb2, 0xe1, 0xb5, 0x18, 0x7a, 0x10, - 0xca, 0xaa, 0xdc, 0xd3, 0x91, 0x11, 0xdf, 0x5e, 0xe1, 0xde, 0x85, 0x38, 0xf4, 0x1a, 0x94, 0x7c, - 0xe6, 0x1c, 0x79, 0x12, 0x98, 0xc9, 0x12, 0x49, 0xc4, 0x30, 0x27, 0xc0, 0x4a, 0xae, 0xf9, 0xae, - 0x01, 0x95, 0xf8, 0x06, 0x55, 0x11, 0xc6, 0x78, 0x18, 0xab, 0xe5, 0x34, 0x3d, 0x17, 0x58, 0x61, - 0x6e, 0xe3, 0x0e, 0xb9, 0x02, 0x63, 0xbe, 0xde, 0x09, 0x1d, 0xa9, 0xf7, 0xc7, 0x4d, 0xb3, 0x86, - 0xdf, 0x4c, 0xfd, 0xc7, 0x31, 0xb5, 0xf9, 0xb7, 0x22, 0x4c, 0x6e, 0x10, 0xf1, 0x26, 0xe3, 0xd7, - 0x9b, 0xcc, 0xa5, 0xf6, 0xee, 0x29, 0x38, 0x7d, 0x0b, 0xca, 0xbc, 0xe7, 0x92, 0x68, 0x83, 0x97, - 0x86, 0x4e, 0x0f, 0x69, 0x7b, 0x71, 0xcf, 0x25, 0xc9, 0x39, 0xca, 0xa7, 0x00, 0x87, 0xe2, 0xd1, - 0xd3, 0x70, 0xd6, 0xca, 0x0c, 0x87, 0xc2, 0xcc, 0x58, 0x51, 0x9e, 0x7d, 0x36, 0x3b, 0x37, 0x0a, - 0x70, 0x9e, 0x16, 0x5d, 0x92, 0x9b, 0x4a, 0x19, 0x97, 0xb9, 0x5c, 0x36, 0x65, 0x46, 0x7d, 0x22, - 0xdc, 0xd0, 0x10, 0x86, 0x63, 0x2c, 0x7a, 0x14, 0x26, 0x04, 0x25, 0x3c, 0xc2, 0xa8, 0xb4, 0x57, - 0xae, 0x4f, 0xab, 0xf6, 0x2d, 0x05, 0xc7, 0x19, 0x2a, 0x14, 0x40, 0x25, 0x60, 0x3d, 0xae, 0xf2, - 0x90, 0xce, 0x64, 0xd7, 0x8e, 0xb7, 0x15, 0xb1, 0xd7, 0x4d, 0xca, 0x7c, 0xb4, 0x19, 0x09, 0xc7, - 0x89, 0x1e, 0xf3, 0x0f, 0x06, 0x9c, 0xcb, 0x30, 0x9d, 0x42, 0x87, 0xb3, 0x9d, 0xed, 0x70, 0x9e, - 0x3e, 0xd6, 0x22, 0x07, 0xf4, 0x38, 0xff, 0x30, 0xe0, 0x7c, 0x86, 0x4e, 0x16, 0x0c, 0x9b, 0xc2, - 0x12, 0xbd, 0x00, 0x3d, 0x0c, 0x63, 0xb2, 0x70, 0xd8, 0x38, 0x60, 0x00, 0xb5, 0xa1, 0xe1, 0x38, - 0xa6, 0x90, 0x5d, 0xb5, 0x7e, 0xf1, 0x42, 0x99, 0xa7, 0x62, 0x2e, 0xd5, 0x55, 0xaf, 0xc6, 0x18, - 0x9c, 0xa2, 0x42, 0xdf, 0x00, 0xc4, 0x89, 0xe5, 0xd2, 0xb7, 0xd4, 0xe3, 0x35, 0x8b, 0xba, 0x3d, - 0x4e, 0x54, 0x24, 0x8e, 0xd5, 0xef, 0xd5, 0xbc, 0x08, 0xf7, 0x51, 0xe0, 0x03, 0xb8, 0xd0, 0x17, - 0x61, 0xb4, 0x4b, 0x82, 0x40, 0x76, 0xe7, 0x25, 0x65, 0xec, 0x59, 0x2d, 0x60, 0x74, 0x3d, 0x04, - 0xe3, 0x08, 0xaf, 0x5e, 0x28, 0x64, 0x16, 0xdd, 0x24, 0x84, 0xa3, 0xcb, 0x30, 0x69, 0xa5, 0xde, - 0x32, 0x04, 0xb3, 0x86, 0x72, 0xfa, 0x73, 0xfb, 0x7b, 0xf3, 0x93, 0xe9, 0xd7, 0x0f, 0x01, 0xce, - 0xd2, 0x21, 0x02, 0x63, 0xd4, 0xd7, 0x03, 0x90, 0xf0, 0xa8, 0x2e, 0x0f, 0x9f, 0x66, 0x15, 0x7f, - 0xb2, 0xc1, 0xf1, 0xe4, 0x23, 0x16, 0x8d, 0xe6, 0xa1, 0xdc, 0x7a, 0xc3, 0xf1, 0xa2, 0x60, 0xac, - 0xc8, 0xb3, 0xbc, 0xf6, 0xc2, 0xd5, 0x8d, 0x00, 0x87, 0x70, 0x24, 0x00, 0x04, 0xd3, 0xd5, 0x58, - 0x54, 0xa2, 0x1e, 0xbf, 0xc6, 0x4b, 0x4d, 0x46, 0x22, 0xd9, 0x38, 0xa5, 0x47, 0xde, 0x16, 0xae, - 0xb5, 0x4d, 0xdc, 0x86, 0x43, 0x64, 0x31, 0x4d, 0xd5, 0x48, 0xa5, 0x78, 0x69, 0x32, 0xbc, 0x2d, - 0xd6, 0xb2, 0x28, 0x9c, 0xa7, 0x35, 0x3f, 0x31, 0xe0, 0x9e, 0x83, 0xa3, 0x11, 0x3d, 0x06, 0x25, - 0x59, 0xaf, 0x69, 0xdf, 0x7b, 0x20, 0xba, 0xbf, 0xb7, 0x76, 0x7d, 0x72, 0x73, 0x6f, 0x3e, 0x7b, - 0x82, 0x12, 0x88, 0x15, 0xf9, 0xd0, 0xad, 0x5e, 0x9c, 0x27, 0x8a, 0x87, 0xd5, 0x9a, 0xa5, 0xe3, - 0xd4, 0x9a, 0x3f, 0x1f, 0xc9, 0x39, 0x9d, 0xbc, 0x73, 0xd1, 0x53, 0x50, 0x71, 0x28, 0x27, 0xb6, - 0x0a, 0x9a, 0x70, 0xa1, 0x73, 0x91, 0xb1, 0x57, 0x23, 0xc4, 0xcd, 0xf4, 0x03, 0x4e, 0x18, 0x90, - 0x0d, 0xa5, 0x16, 0x67, 0x5d, 0xdd, 0x32, 0x1d, 0x2f, 0x21, 0xc8, 0x18, 0x48, 0x16, 0x7f, 0x8d, - 0xb3, 0x2e, 0x56, 0xc2, 0xd1, 0xab, 0x50, 0x10, 0x4c, 0x4f, 0x59, 0x4f, 0x40, 0x05, 0x68, 0x15, - 0x85, 0x2d, 0x86, 0x0b, 0x82, 0xc9, 0xe8, 0x09, 0xb2, 0x3e, 0x7b, 0xf9, 0x88, 0x3e, 0x9b, 0x44, - 0x4f, 0xec, 0xa8, 0xb1, 0x68, 0x35, 0x1f, 0xcf, 0xe5, 0x99, 0x24, 0xd5, 0xf7, 0x65, 0xa6, 0x97, - 0x60, 0xc4, 0x0a, 0xcf, 0x64, 0x44, 0x9d, 0xc9, 0xd7, 0xd4, 0x3c, 0x3a, 0x3a, 0x8c, 0x85, 0x5b, - 0xbc, 0xfd, 0xe7, 0x4e, 0xfc, 0x2e, 0xbe, 0x2a, 0x4f, 0x38, 0x64, 0xc2, 0x5a, 0x1c, 0x7a, 0x12, - 0x26, 0x89, 0x67, 0x6d, 0xbb, 0x64, 0x8d, 0xb5, 0xdb, 0xd4, 0x6b, 0xcf, 0x8e, 0xaa, 0xcb, 0xee, - 0x6e, 0x6d, 0xcb, 0xe4, 0x4a, 0x1a, 0x89, 0xb3, 0xb4, 0x07, 0x25, 0xe6, 0xb1, 0x21, 0x12, 0x73, - 0xe4, 0xe7, 0x95, 0x81, 0x7e, 0xfe, 0x06, 0x8c, 0xbb, 0x71, 0x9d, 0x19, 0xcc, 0x82, 0x3a, 0x8e, - 0x27, 0x86, 0x3d, 0x8e, 0xa4, 0x54, 0x4d, 0x26, 0xa4, 0x09, 0x2c, 0xc0, 0x69, 0x1d, 0xe6, 0x7b, - 0x45, 0x40, 0x19, 0x27, 0x91, 0xc9, 0x27, 0x40, 0xef, 0x18, 0x30, 0xe9, 0xa5, 0xc1, 0x3a, 0xbf, - 0x9e, 0x54, 0xa6, 0x8f, 0x37, 0x3c, 0x8b, 0xcf, 0xea, 0x44, 0x3e, 0x4c, 0x08, 0x6e, 0xb5, 0x5a, - 0xd4, 0x56, 0x56, 0xe9, 0x38, 0x7b, 0xfc, 0x16, 0x36, 0xa8, 0xaf, 0x31, 0xaa, 0xb1, 0x07, 0x6c, - 0xa5, 0xb8, 0x53, 0xb3, 0xe9, 0x14, 0x14, 0x67, 0x34, 0xa0, 0xb7, 0x0d, 0x98, 0x96, 0x55, 0x58, - 0x9a, 0x44, 0x8f, 0xdb, 0x9e, 0xb8, 0x7d, 0xb5, 0x38, 0x27, 0x21, 0x69, 0x6a, 0xf2, 0x18, 0xdc, - 0xa7, 0xcd, 0xfc, 0x8b, 0x01, 0x33, 0x7d, 0x27, 0xd2, 0x3b, 0x8d, 0xd7, 0x1a, 0x2e, 0x94, 0x65, - 0x39, 0x11, 0x65, 0xd1, 0xd5, 0x63, 0x9d, 0x75, 0x52, 0xc8, 0x24, 0xa5, 0x8f, 0x84, 0x05, 0x38, - 0x54, 0x62, 0x2e, 0xc0, 0x64, 0x66, 0x60, 0x72, 0xf8, 0x14, 0xd1, 0x7c, 0xbf, 0x0c, 0xd3, 0x91, - 0xdc, 0x60, 0xb3, 0xd7, 0xed, 0x5a, 0xfc, 0x34, 0x0a, 0xff, 0xef, 0x1b, 0x70, 0x36, 0xed, 0x98, - 0x34, 0xde, 0xa2, 0xfa, 0xb1, 0xb6, 0x28, 0xf4, 0x8d, 0xf3, 0x5a, 0xf7, 0xd9, 0x8d, 0xac, 0x0a, - 0x9c, 0xd7, 0x89, 0x7e, 0x63, 0xc0, 0xfd, 0xa1, 0x16, 0xfd, 0xda, 0x2b, 0xc7, 0xa1, 0x1d, 0xf5, - 0x24, 0x8c, 0xfa, 0x7f, 0x6d, 0xd4, 0xfd, 0x4b, 0xb7, 0xd0, 0x87, 0x6f, 0x69, 0x0d, 0xfa, 0x85, - 0x01, 0x77, 0x87, 0x04, 0x79, 0x3b, 0x4b, 0x27, 0x66, 0xe7, 0x05, 0x6d, 0xe7, 0xdd, 0x4b, 0x07, - 0x29, 0xc2, 0x07, 0xeb, 0x97, 0x2d, 0x4c, 0x37, 0x6a, 0xb2, 0x55, 0xb5, 0x74, 0x04, 0x63, 0xfa, - 0xbb, 0xf4, 0xa4, 0xcc, 0x89, 0x71, 0x38, 0xd1, 0x63, 0xbe, 0x0a, 0x77, 0x35, 0xad, 0x36, 0xf5, - 0x54, 0xd5, 0xbc, 0x4a, 0xc4, 0xf3, 0xbe, 0xfc, 0x13, 0x84, 0xa3, 0xaa, 0x76, 0xe8, 0xf6, 0xc5, - 0xf4, 0xa8, 0xaa, 0x4d, 0xb0, 0xc2, 0xc8, 0xee, 0xdf, 0xa5, 0x5d, 0x2a, 0x74, 0x55, 0x1f, 0x87, - 0xd3, 0x9a, 0x04, 0xe2, 0x10, 0x67, 0x5a, 0x30, 0x91, 0xee, 0xe0, 0xef, 0xc4, 0x4c, 0xfe, 0xef, - 0x05, 0x88, 0xa6, 0x8d, 0xe8, 0xd1, 0x54, 0xeb, 0x1e, 0xaa, 0x98, 0x3d, 0xbc, 0x6d, 0x47, 0x1b, - 0x7a, 0x68, 0x50, 0x38, 0x24, 0x4e, 0x7b, 0x82, 0xba, 0xd5, 0xf0, 0x73, 0xb2, 0x6a, 0xc3, 0x13, - 0xcf, 0xf3, 0x4d, 0xc1, 0xa9, 0xd7, 0x0e, 0xc7, 0x25, 0xa9, 0x11, 0xc3, 0x17, 0x60, 0x94, 0x78, - 0x6a, 0x1e, 0xa1, 0x0a, 0xa4, 0x72, 0x38, 0x11, 0x5d, 0x09, 0x41, 0x38, 0xc2, 0xc9, 0x96, 0x98, - 0xda, 0x5d, 0x5f, 0x16, 0xa9, 0xaa, 0x88, 0x2c, 0x87, 0x2d, 0x71, 0x63, 0x79, 0xbd, 0xa9, 0x0a, - 0xd7, 0x18, 0x1b, 0x51, 0x2e, 0x47, 0x53, 0xe0, 0x14, 0xa5, 0x84, 0xe1, 0x18, 0xab, 0x28, 0xdb, - 0x5a, 0xe6, 0x48, 0x8a, 0x72, 0x35, 0x96, 0xa9, 0xb1, 0xe8, 0x8a, 0x7e, 0x25, 0xa8, 0x9b, 0x18, - 0x55, 0x72, 0x54, 0x72, 0x6f, 0xf5, 0xa2, 0x39, 0x55, 0x86, 0xd2, 0x24, 0x30, 0x9d, 0xef, 0x07, - 0xee, 0xc4, 0xb9, 0xbe, 0x57, 0x82, 0xf3, 0x9b, 0x3d, 0x5f, 0xee, 0x68, 0xf8, 0x85, 0xc1, 0x32, - 0x73, 0x5d, 0x5d, 0xe2, 0xde, 0xf9, 0xdb, 0xf5, 0x15, 0xa8, 0x90, 0x1b, 0x3e, 0xe5, 0xc4, 0x59, - 0x8a, 0x1c, 0xe3, 0x4b, 0xb7, 0xa7, 0x62, 0x8b, 0x76, 0x49, 0xb2, 0xb4, 0x95, 0x48, 0x08, 0x4e, - 0xe4, 0xc9, 0xbd, 0x08, 0xa8, 0x67, 0x13, 0x49, 0xaa, 0x1b, 0x8c, 0x98, 0x61, 0x33, 0x42, 0xe0, - 0x84, 0x46, 0x36, 0x71, 0xad, 0xf8, 0x9b, 0x0c, 0xe5, 0x2c, 0x47, 0x68, 0xe2, 0xf2, 0xdf, 0x76, - 0x24, 0x3b, 0x90, 0xc0, 0x70, 0x4a, 0x0f, 0xfa, 0xb1, 0x01, 0x53, 0x56, 0xf6, 0xb3, 0x8a, 0xf0, - 0x1d, 0xc4, 0xfa, 0xd1, 0x54, 0x0f, 0xf8, 0x44, 0xa4, 0x7e, 0x8f, 0xb6, 0x63, 0x2a, 0xf7, 0x7d, - 0x45, 0x4e, 0xb9, 0xf9, 0xa9, 0x01, 0xf7, 0x0d, 0xf0, 0x88, 0x53, 0x18, 0xbc, 0xb8, 0xd9, 0xc1, - 0xcb, 0xd0, 0x75, 0xc8, 0x00, 0xcb, 0x07, 0x8c, 0x60, 0x7e, 0x56, 0x80, 0x07, 0x06, 0x70, 0x1c, - 0x79, 0x18, 0xf3, 0x24, 0x4c, 0x46, 0xff, 0xd3, 0x61, 0x98, 0x54, 0xbd, 0x69, 0x24, 0xce, 0xd2, - 0x46, 0xaa, 0xd4, 0xcd, 0x52, 0xec, 0x57, 0x15, 0xde, 0x2e, 0x11, 0x85, 0xf4, 0x70, 0x9b, 0x75, - 0x7d, 0x97, 0x08, 0x12, 0x76, 0xc8, 0x63, 0x89, 0x87, 0x2f, 0x47, 0x08, 0x9c, 0xd0, 0xc8, 0x6c, - 0x42, 0x38, 0x67, 0x5c, 0x79, 0x58, 0x6a, 0x96, 0xbc, 0x22, 0x81, 0x38, 0xc4, 0x99, 0xff, 0x34, - 0xe0, 0xc2, 0x80, 0x4d, 0x39, 0xb5, 0x72, 0x74, 0x27, 0x5b, 0x8e, 0xbe, 0x70, 0x42, 0x6e, 0x70, - 0x58, 0x61, 0x5a, 0xdf, 0xfa, 0xe0, 0xe3, 0xb9, 0x33, 0x1f, 0x7e, 0x3c, 0x77, 0xe6, 0xa3, 0x8f, - 0xe7, 0xce, 0xbc, 0xbd, 0x3f, 0x67, 0x7c, 0xb0, 0x3f, 0x67, 0x7c, 0xb8, 0x3f, 0x67, 0x7c, 0xb4, - 0x3f, 0x67, 0xfc, 0x69, 0x7f, 0xce, 0xf8, 0xe9, 0x9f, 0xe7, 0xce, 0xbc, 0x5c, 0x1d, 0xee, 0x13, - 0xf4, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x4f, 0x63, 0x69, 0xf0, 0xb3, 0x2e, 0x00, 0x00, + 0xf9, 0xdb, 0x9e, 0x19, 0x3f, 0x3e, 0x3f, 0xd6, 0x5b, 0x4e, 0xb2, 0xfe, 0x25, 0x59, 0x7b, 0xd3, + 0xf9, 0x11, 0x2d, 0x28, 0xcc, 0xc4, 0x26, 0xc9, 0x2e, 0x79, 0x81, 0xc7, 0xeb, 0x75, 0x86, 0xd8, + 0xce, 0xa4, 0xec, 0x28, 0x52, 0x42, 0x42, 0xda, 0xdd, 0x35, 0x33, 0xc5, 0xf6, 0x74, 0x75, 0xaa, + 0x6b, 0x9c, 0x75, 0x0e, 0x28, 0x28, 0x70, 0x08, 0xaf, 0x20, 0x84, 0x84, 0xb8, 0x71, 0xe3, 0xc2, + 0x5f, 0x90, 0x1b, 0x07, 0xa4, 0x1c, 0x83, 0x10, 0x22, 0x27, 0x8b, 0x18, 0x11, 0x94, 0x03, 0x17, + 0x6e, 0x2c, 0x42, 0x42, 0x55, 0x5d, 0xdd, 0x5d, 0x3d, 0xe3, 0x59, 0xef, 0xd8, 0x5e, 0x23, 0x91, + 0x9c, 0x66, 0xfa, 0x7b, 0x57, 0xd5, 0xf7, 0xd5, 0xf7, 0xe8, 0x86, 0x67, 0x9c, 0x40, 0x70, 0xe2, + 0x94, 0x29, 0xab, 0xc4, 0xff, 0x2a, 0xe1, 0xf5, 0x66, 0xc5, 0x09, 0x69, 0x54, 0x71, 0x59, 0x20, + 0x38, 0xf3, 0x43, 0xdf, 0x09, 0x48, 0x65, 0x67, 0x61, 0x9b, 0x08, 0x67, 0xb1, 0xd2, 0x24, 0x01, + 0xe1, 0x8e, 0x20, 0x5e, 0x39, 0xe4, 0x4c, 0x30, 0x54, 0x8e, 0xb9, 0xbe, 0x45, 0x99, 0xfe, 0x57, + 0x0e, 0xaf, 0x37, 0xcb, 0x92, 0xbf, 0x6c, 0xf2, 0x97, 0x35, 0xff, 0xbd, 0x57, 0xfa, 0xeb, 0x8b, + 0x84, 0x23, 0xa2, 0xca, 0xce, 0x82, 0xe3, 0x87, 0x2d, 0x67, 0xa1, 0x5b, 0xd3, 0xbd, 0x5f, 0x6e, + 0x52, 0xd1, 0xea, 0x6c, 0x97, 0x5d, 0xd6, 0xae, 0x34, 0x59, 0x93, 0x55, 0x14, 0x78, 0xbb, 0xd3, + 0x50, 0x4f, 0xea, 0x41, 0xfd, 0xd3, 0xe4, 0x8f, 0x5e, 0xbf, 0x12, 0x29, 0x2d, 0x21, 0x6d, 0x3b, + 0x6e, 0x8b, 0x06, 0x84, 0xef, 0x66, 0xba, 0xda, 0x44, 0x38, 0x95, 0x9d, 0x5e, 0x25, 0x95, 0x7e, + 0x5c, 0xbc, 0x13, 0x08, 0xda, 0x26, 0x3d, 0x0c, 0x8f, 0x1f, 0xc6, 0x10, 0xb9, 0x2d, 0xd2, 0x76, + 0x7a, 0xf8, 0xbe, 0xd2, 0x8f, 0xaf, 0x23, 0xa8, 0x5f, 0xa1, 0x81, 0x88, 0x04, 0xef, 0x66, 0xb2, + 0xff, 0x66, 0xc1, 0xc4, 0x92, 0xe7, 0x71, 0x12, 0x45, 0xab, 0x9c, 0x75, 0x42, 0xf4, 0x3a, 0x8c, + 0xca, 0x95, 0x78, 0x8e, 0x70, 0x66, 0xad, 0x8b, 0xd6, 0xa5, 0xf1, 0xc5, 0x47, 0xca, 0xb1, 0xe0, + 0xb2, 0x29, 0x38, 0x3b, 0x13, 0x49, 0x5d, 0xde, 0x59, 0x28, 0x3f, 0xbf, 0xfd, 0x6d, 0xe2, 0x8a, + 0x75, 0x22, 0x9c, 0x2a, 0xfa, 0x60, 0x6f, 0xfe, 0xcc, 0xfe, 0xde, 0x3c, 0x64, 0x30, 0x9c, 0x4a, + 0x45, 0x1d, 0x98, 0x68, 0x4a, 0x55, 0xeb, 0xa4, 0xbd, 0x4d, 0x78, 0x34, 0x3b, 0x74, 0xb1, 0x70, + 0x69, 0x7c, 0xf1, 0xc9, 0x01, 0x8f, 0xbd, 0xbc, 0x9a, 0xc9, 0xa8, 0xde, 0xa5, 0x15, 0x4e, 0x18, + 0xc0, 0x08, 0xe7, 0xd4, 0xd8, 0x7f, 0xb0, 0x60, 0xda, 0x5c, 0xe9, 0x1a, 0x8d, 0x04, 0xfa, 0x66, + 0xcf, 0x6a, 0xcb, 0xb7, 0xb7, 0x5a, 0xc9, 0xad, 0xd6, 0x3a, 0xad, 0x55, 0x8f, 0x26, 0x10, 0x63, + 0xa5, 0x0e, 0x94, 0xa8, 0x20, 0xed, 0x64, 0x89, 0x4f, 0x0d, 0xba, 0x44, 0xd3, 0xdc, 0xea, 0xa4, + 0x56, 0x54, 0xaa, 0x49, 0x91, 0x38, 0x96, 0x6c, 0xbf, 0x5b, 0x80, 0x73, 0x26, 0x59, 0xdd, 0x11, + 0x6e, 0xeb, 0x14, 0x0e, 0xf1, 0x7b, 0x16, 0x9c, 0x73, 0x3c, 0x8f, 0x78, 0xab, 0x27, 0x7c, 0x94, + 0xff, 0xa7, 0xd5, 0xca, 0x55, 0xe5, 0xa5, 0xe3, 0x5e, 0x85, 0xe8, 0x07, 0x16, 0xcc, 0x70, 0xd2, + 0x66, 0x3b, 0x5d, 0x86, 0x14, 0x8e, 0x6f, 0xc8, 0x7d, 0xda, 0x90, 0x19, 0xdc, 0x2b, 0x1f, 0x1f, + 0xa4, 0xd4, 0xfe, 0xd4, 0x82, 0xa9, 0xa5, 0x30, 0xf4, 0x29, 0xf1, 0xb6, 0xd8, 0xff, 0x78, 0x34, + 0xfd, 0xc9, 0x02, 0x94, 0x5f, 0xeb, 0x29, 0xc4, 0x93, 0x9b, 0x8f, 0xa7, 0x67, 0x06, 0x8e, 0xa7, + 0x9c, 0xc1, 0x7d, 0x22, 0xea, 0x87, 0x05, 0x98, 0xc9, 0x13, 0x7e, 0x1e, 0x53, 0xff, 0xbd, 0x98, + 0x7a, 0x03, 0x66, 0xaa, 0x4e, 0x44, 0xdd, 0xa5, 0x8e, 0x68, 0x91, 0x40, 0x50, 0xd7, 0x11, 0x94, + 0x05, 0xe8, 0x61, 0x18, 0xed, 0x44, 0x84, 0x07, 0x4e, 0x9b, 0xa8, 0xc3, 0x18, 0xcb, 0xfc, 0xe6, + 0x45, 0x0d, 0xc7, 0x29, 0x85, 0xa4, 0x0e, 0x9d, 0x28, 0x7a, 0x93, 0x71, 0x6f, 0x76, 0x28, 0x4f, + 0x5d, 0xd7, 0x70, 0x9c, 0x52, 0xd8, 0x0b, 0x30, 0x5d, 0xed, 0x04, 0x9e, 0x4f, 0xae, 0x51, 0x9f, + 0x6c, 0x12, 0xbe, 0x43, 0x38, 0xba, 0x00, 0x85, 0x0e, 0xf7, 0xb5, 0xaa, 0x71, 0xcd, 0x5c, 0x78, + 0x11, 0xaf, 0x61, 0x09, 0xb7, 0xdf, 0x1b, 0x82, 0x0b, 0x31, 0x4f, 0x4c, 0x2f, 0xad, 0x5d, 0x66, + 0x41, 0x83, 0x36, 0x3b, 0x3c, 0x36, 0xf8, 0x31, 0x18, 0xdf, 0x26, 0x0e, 0x27, 0x7c, 0x8b, 0x5d, + 0x27, 0x81, 0x16, 0x34, 0xa3, 0x05, 0x8d, 0x57, 0x33, 0x14, 0x36, 0xe9, 0xd0, 0x43, 0x30, 0xec, + 0x84, 0xf4, 0x39, 0xb2, 0xab, 0xed, 0x9e, 0xd2, 0x1c, 0xc3, 0x4b, 0xf5, 0xda, 0x73, 0x64, 0x17, + 0x6b, 0x2c, 0xfa, 0x89, 0x05, 0x33, 0xdb, 0xbd, 0xfb, 0x34, 0x5b, 0x50, 0x8e, 0xba, 0x3c, 0xe8, + 0x99, 0x1d, 0xb0, 0xe5, 0xd5, 0xf3, 0xf2, 0xdc, 0x0e, 0x40, 0xe0, 0x83, 0x14, 0xdb, 0xbf, 0x2a, + 0xc2, 0xcc, 0xb2, 0xdf, 0x89, 0x04, 0xe1, 0x39, 0xe7, 0xba, 0xf3, 0x51, 0xf4, 0x5d, 0x0b, 0xa6, + 0x49, 0xa3, 0x41, 0x5c, 0x41, 0x77, 0xc8, 0x09, 0x06, 0xd1, 0xac, 0xd6, 0x3a, 0xbd, 0xd2, 0x25, + 0x1c, 0xf7, 0xa8, 0x43, 0xdf, 0x81, 0x73, 0x29, 0xac, 0x56, 0xaf, 0xfa, 0xcc, 0xbd, 0x9e, 0xc4, + 0xcf, 0x63, 0x83, 0xda, 0x50, 0xab, 0x6f, 0x10, 0x91, 0x85, 0xf0, 0x4a, 0xb7, 0x5c, 0xdc, 0xab, + 0x0a, 0x5d, 0x81, 0x09, 0xc1, 0x84, 0xe3, 0x27, 0xcb, 0x2f, 0x5e, 0xb4, 0x2e, 0x15, 0xb2, 0x7b, + 0x7d, 0xcb, 0xc0, 0xe1, 0x1c, 0x25, 0x5a, 0x04, 0x50, 0xcf, 0x75, 0xa7, 0x49, 0xa2, 0xd9, 0x92, + 0xe2, 0x4b, 0xf7, 0x7b, 0x2b, 0xc5, 0x60, 0x83, 0x4a, 0xfa, 0xb6, 0xdb, 0xe1, 0x9c, 0x04, 0x42, + 0x3e, 0xcf, 0x0e, 0x2b, 0xa6, 0xd4, 0xb7, 0x97, 0x33, 0x14, 0x36, 0xe9, 0xec, 0x4f, 0x2c, 0x18, + 0x5f, 0x69, 0x7e, 0x06, 0x2a, 0xcf, 0xdf, 0x5b, 0x70, 0xd6, 0x58, 0xe8, 0x29, 0x24, 0xca, 0xd7, + 0xf3, 0x89, 0x72, 0xe0, 0x15, 0x1a, 0xd6, 0xf6, 0xc9, 0x92, 0x3f, 0x2a, 0xc0, 0xb4, 0x41, 0x15, + 0xa7, 0x48, 0x0f, 0x80, 0xa5, 0xfb, 0x7e, 0xa2, 0x67, 0x68, 0xc8, 0xfd, 0x3c, 0x4d, 0x1e, 0x90, + 0x26, 0x7d, 0x38, 0xbf, 0x72, 0x43, 0xc8, 0x74, 0xe7, 0xaf, 0x04, 0x82, 0x8a, 0x5d, 0x4c, 0x1a, + 0x84, 0x93, 0xc0, 0x25, 0xe8, 0x22, 0x14, 0x8d, 0x34, 0x39, 0xa1, 0x45, 0x17, 0x37, 0x64, 0x8a, + 0x54, 0x18, 0x54, 0x81, 0x31, 0xf9, 0x1b, 0x85, 0x8e, 0x4b, 0x74, 0x9e, 0x39, 0xa7, 0xc9, 0xc6, + 0x36, 0x12, 0x04, 0xce, 0x68, 0xec, 0x7f, 0x59, 0x30, 0xad, 0xd4, 0x2f, 0x45, 0x11, 0x73, 0x69, + 0x9c, 0xe1, 0x4e, 0xa5, 0x3e, 0x9a, 0x76, 0xb4, 0x46, 0xbd, 0xfe, 0x23, 0x97, 0x82, 0x8a, 0x3b, + 0xdd, 0xa4, 0xec, 0x72, 0x5f, 0xea, 0x92, 0x8f, 0x7b, 0x34, 0xda, 0xef, 0x17, 0x61, 0xdc, 0xd8, + 0x7c, 0xf4, 0x12, 0x14, 0x42, 0xe6, 0xe9, 0x35, 0x0f, 0xdc, 0xe3, 0xd5, 0x99, 0x97, 0x99, 0x31, + 0x22, 0xab, 0x0a, 0x09, 0x91, 0x12, 0xd1, 0x3b, 0x16, 0x4c, 0x91, 0xdc, 0xa9, 0xaa, 0xd3, 0x19, + 0x5f, 0x5c, 0x1d, 0x38, 0x9e, 0x0f, 0xf6, 0x8d, 0x2a, 0xda, 0xdf, 0x9b, 0x9f, 0xea, 0x42, 0x76, + 0xa9, 0x44, 0x0f, 0x41, 0x81, 0x86, 0xb1, 0x5b, 0x4f, 0x54, 0xef, 0x92, 0x06, 0xd6, 0xea, 0xd1, + 0xcd, 0xbd, 0xf9, 0xb1, 0x5a, 0x5d, 0x37, 0x9e, 0x58, 0x12, 0xa0, 0xd7, 0xa0, 0x14, 0x32, 0x2e, + 0x64, 0xb2, 0x91, 0x27, 0xf2, 0xd5, 0x41, 0x6d, 0x94, 0x9e, 0xe6, 0xd5, 0x19, 0x17, 0xd9, 0x8d, + 0x23, 0x9f, 0x22, 0x1c, 0x8b, 0x45, 0xaf, 0x40, 0x31, 0x60, 0x1e, 0x51, 0x39, 0x69, 0x7c, 0xf1, + 0xe9, 0x81, 0xc5, 0x33, 0x8f, 0x64, 0x0b, 0x1f, 0x55, 0x21, 0x20, 0x41, 0x4a, 0x28, 0x6a, 0xc2, + 0x48, 0x44, 0xf8, 0x0e, 0x75, 0xe3, 0xf4, 0x35, 0xbe, 0xf8, 0xf5, 0x41, 0xe5, 0x6f, 0xc6, 0xec, + 0x99, 0x8a, 0xf1, 0xfd, 0xbd, 0xf9, 0x91, 0x04, 0x9a, 0x48, 0xb7, 0x7f, 0x6d, 0xc1, 0x54, 0xde, + 0xf7, 0xf2, 0xe1, 0x67, 0x1d, 0x1e, 0x7e, 0x69, 0x44, 0x0f, 0xf5, 0x8d, 0xe8, 0x2a, 0x14, 0x3a, + 0xd4, 0x53, 0xd5, 0xdf, 0x58, 0xf5, 0x91, 0xb4, 0x5c, 0xad, 0x5d, 0xbd, 0xb9, 0x37, 0xff, 0x40, + 0xbf, 0x31, 0x91, 0xd8, 0x0d, 0x49, 0x54, 0x7e, 0xb1, 0x76, 0x15, 0x4b, 0x66, 0xfb, 0x2d, 0x98, + 0x78, 0x76, 0x6b, 0xab, 0x5e, 0xe7, 0x4c, 0x30, 0x97, 0xf9, 0x52, 0x6b, 0x8b, 0x45, 0xa2, 0xfb, + 0x1e, 0x79, 0x96, 0x45, 0x02, 0x2b, 0x8c, 0x2c, 0x56, 0xdb, 0x44, 0xb4, 0x98, 0xd7, 0x5d, 0xac, + 0xae, 0x2b, 0x28, 0xd6, 0x58, 0x29, 0x29, 0x74, 0x44, 0x4b, 0x9b, 0x97, 0x4a, 0xaa, 0x3b, 0xa2, + 0x85, 0x15, 0xc6, 0xfe, 0xad, 0x05, 0x23, 0xba, 0x98, 0x41, 0x2f, 0x41, 0xd1, 0xa5, 0x1e, 0xd7, + 0xf1, 0x75, 0xc4, 0xf2, 0x29, 0x55, 0xb2, 0x5c, 0xbb, 0x8a, 0xb1, 0x12, 0x88, 0x5e, 0x85, 0x61, + 0x72, 0xc3, 0x25, 0xa1, 0xd0, 0x77, 0xc8, 0x11, 0x45, 0xa7, 0xab, 0x5c, 0x51, 0xc2, 0xb0, 0x16, + 0x6a, 0xff, 0xdb, 0x02, 0x54, 0xab, 0x7f, 0x76, 0xaf, 0xc9, 0x06, 0x94, 0xd4, 0x06, 0xa1, 0x07, + 0x61, 0x88, 0x86, 0x6a, 0xad, 0x13, 0xd5, 0x99, 0xfd, 0xbd, 0xf9, 0xa1, 0x5a, 0x3d, 0x7f, 0x7d, + 0x0c, 0xd1, 0x50, 0x56, 0xac, 0x21, 0x27, 0x0d, 0x7a, 0x63, 0x8d, 0x04, 0x4d, 0xd1, 0x52, 0x1e, + 0x54, 0xca, 0xaa, 0xab, 0xba, 0x81, 0xc3, 0x39, 0x4a, 0xbb, 0x05, 0xb0, 0x76, 0x39, 0xf5, 0xd2, + 0x97, 0xa1, 0xd8, 0x12, 0x22, 0x3c, 0xea, 0x6d, 0x6c, 0x7a, 0x7c, 0x7c, 0x49, 0x48, 0x08, 0x56, + 0x32, 0xed, 0x5f, 0x5a, 0x80, 0xd6, 0x3b, 0xbe, 0xec, 0x71, 0x22, 0xa1, 0x56, 0x59, 0x0b, 0x1a, + 0x0c, 0x3d, 0x08, 0x25, 0x55, 0xee, 0xe9, 0xc8, 0x48, 0x6f, 0xaf, 0x78, 0xef, 0x62, 0x1c, 0x7a, + 0x0d, 0x8a, 0x21, 0xf3, 0x8e, 0x3c, 0x09, 0xcc, 0x65, 0x89, 0x2c, 0x62, 0x98, 0x17, 0x61, 0x25, + 0xd7, 0x7e, 0xd7, 0x82, 0xb1, 0xf4, 0x06, 0x55, 0x11, 0xc6, 0x78, 0x1c, 0xab, 0x25, 0x93, 0x9e, + 0x0b, 0xac, 0x30, 0xb7, 0x71, 0x87, 0x5c, 0x81, 0xd1, 0x50, 0xef, 0x84, 0x8e, 0xd4, 0xfb, 0xd3, + 0xa6, 0x59, 0xc3, 0x6f, 0x1a, 0xff, 0x71, 0x4a, 0x6d, 0xff, 0xbd, 0x00, 0x93, 0x1b, 0x44, 0xbc, + 0xc9, 0xf8, 0xf5, 0x3a, 0xf3, 0xa9, 0xbb, 0x7b, 0x0a, 0x4e, 0xdf, 0x80, 0x12, 0xef, 0xf8, 0x24, + 0xd9, 0xe0, 0xa5, 0x81, 0xd3, 0x83, 0x69, 0x2f, 0xee, 0xf8, 0x24, 0x3b, 0x47, 0xf9, 0x14, 0xe1, + 0x58, 0x3c, 0x7a, 0x1a, 0xce, 0x3a, 0xb9, 0xe1, 0x50, 0x9c, 0x19, 0xc7, 0x94, 0x67, 0x9f, 0xcd, + 0xcf, 0x8d, 0x22, 0xdc, 0x4d, 0x8b, 0x2e, 0xc9, 0x4d, 0xa5, 0x8c, 0xcb, 0x5c, 0x2e, 0x9b, 0x32, + 0xab, 0x3a, 0x11, 0x6f, 0x68, 0x0c, 0xc3, 0x29, 0x16, 0x3d, 0x0a, 0x13, 0x82, 0x12, 0x9e, 0x60, + 0x54, 0xda, 0x2b, 0x55, 0xa7, 0x55, 0xfb, 0x66, 0xc0, 0x71, 0x8e, 0x0a, 0x45, 0x30, 0x16, 0xb1, + 0x0e, 0x57, 0x79, 0x48, 0x67, 0xb2, 0x6b, 0xc7, 0xdb, 0x8a, 0xd4, 0xeb, 0x26, 0x65, 0x3e, 0xda, + 0x4c, 0x84, 0xe3, 0x4c, 0x8f, 0xfd, 0x47, 0x0b, 0xce, 0xe5, 0x98, 0x4e, 0xa1, 0xc3, 0xd9, 0xce, + 0x77, 0x38, 0x4f, 0x1f, 0x6b, 0x91, 0x7d, 0x7a, 0x9c, 0x7f, 0x58, 0x70, 0x3e, 0x47, 0x27, 0x0b, + 0x86, 0x4d, 0xe1, 0x88, 0x4e, 0x84, 0x1e, 0x86, 0x51, 0x59, 0x38, 0x6c, 0x1c, 0x30, 0x80, 0xda, + 0xd0, 0x70, 0x9c, 0x52, 0xc8, 0xae, 0x5a, 0xbf, 0x78, 0xa1, 0x2c, 0x50, 0x31, 0x67, 0x74, 0xd5, + 0xab, 0x29, 0x06, 0x1b, 0x54, 0xe8, 0x1b, 0x80, 0x38, 0x71, 0x7c, 0xfa, 0x96, 0x7a, 0xbc, 0xe6, + 0x50, 0xbf, 0xc3, 0x89, 0x8a, 0xc4, 0xd1, 0xea, 0xbd, 0x9a, 0x17, 0xe1, 0x1e, 0x0a, 0x7c, 0x00, + 0x17, 0xfa, 0x22, 0x8c, 0xb4, 0x49, 0x14, 0xc9, 0xee, 0xbc, 0xa8, 0x8c, 0x3d, 0xab, 0x05, 0x8c, + 0xac, 0xc7, 0x60, 0x9c, 0xe0, 0xd5, 0x0b, 0x85, 0xdc, 0xa2, 0xeb, 0x84, 0x70, 0x74, 0x19, 0x26, + 0x1d, 0xe3, 0x2d, 0x43, 0x34, 0x6b, 0x29, 0xa7, 0x3f, 0xb7, 0xbf, 0x37, 0x3f, 0x69, 0xbe, 0x7e, + 0x88, 0x70, 0x9e, 0x0e, 0x11, 0x18, 0xa5, 0xa1, 0x1e, 0x80, 0xc4, 0x47, 0x75, 0x79, 0xf0, 0x34, + 0xab, 0xf8, 0xb3, 0x0d, 0x4e, 0x27, 0x1f, 0xa9, 0x68, 0x34, 0x0f, 0xa5, 0xc6, 0x1b, 0x5e, 0x90, + 0x04, 0xe3, 0x98, 0x3c, 0xcb, 0x6b, 0x2f, 0x5c, 0xdd, 0x88, 0x70, 0x0c, 0x47, 0x02, 0x40, 0x30, + 0x5d, 0x8d, 0x25, 0x25, 0xea, 0xf1, 0x6b, 0x3c, 0x63, 0x32, 0x92, 0xc8, 0xc6, 0x86, 0x1e, 0x79, + 0x5b, 0xf8, 0xce, 0x36, 0xf1, 0x6b, 0x1e, 0x91, 0xc5, 0x34, 0x55, 0x23, 0x95, 0xc2, 0xa5, 0xc9, + 0xf8, 0xb6, 0x58, 0xcb, 0xa3, 0x70, 0x37, 0xad, 0xfd, 0x89, 0x05, 0xf7, 0x1c, 0x1c, 0x8d, 0xe8, + 0x31, 0x28, 0xca, 0x7a, 0x4d, 0xfb, 0xde, 0x03, 0xc9, 0xfd, 0xbd, 0xb5, 0x1b, 0x92, 0x9b, 0x7b, + 0xf3, 0xf9, 0x13, 0x94, 0x40, 0xac, 0xc8, 0x07, 0x6e, 0xf5, 0xd2, 0x3c, 0x51, 0x38, 0xac, 0xd6, + 0x2c, 0x1e, 0xa7, 0xd6, 0xfc, 0xf9, 0x70, 0x97, 0xd3, 0xc9, 0x3b, 0x17, 0x3d, 0x05, 0x63, 0x1e, + 0xe5, 0xc4, 0x55, 0x41, 0x13, 0x2f, 0x74, 0x2e, 0x31, 0xf6, 0x6a, 0x82, 0xb8, 0x69, 0x3e, 0xe0, + 0x8c, 0x01, 0xb9, 0x50, 0x6c, 0x70, 0xd6, 0xd6, 0x2d, 0xd3, 0xf1, 0x12, 0x82, 0x8c, 0x81, 0x6c, + 0xf1, 0xd7, 0x38, 0x6b, 0x63, 0x25, 0x1c, 0xbd, 0x0a, 0x43, 0x82, 0xe9, 0x29, 0xeb, 0x09, 0xa8, + 0x00, 0xad, 0x62, 0x68, 0x8b, 0xe1, 0x21, 0xc1, 0x64, 0xf4, 0x44, 0x79, 0x9f, 0xbd, 0x7c, 0x44, + 0x9f, 0xcd, 0xa2, 0x27, 0x75, 0xd4, 0x54, 0xb4, 0x9a, 0x8f, 0x77, 0xe5, 0x99, 0x2c, 0xd5, 0xf7, + 0x64, 0xa6, 0x97, 0x60, 0xd8, 0x89, 0xcf, 0x64, 0x58, 0x9d, 0xc9, 0xd7, 0xd4, 0x3c, 0x3a, 0x39, + 0x8c, 0x85, 0x5b, 0xbc, 0xfd, 0xe7, 0x5e, 0xfa, 0x2e, 0xbe, 0x2c, 0x4f, 0x38, 0x66, 0xc2, 0x5a, + 0x1c, 0x7a, 0x12, 0x26, 0x49, 0xe0, 0x6c, 0xfb, 0x64, 0x8d, 0x35, 0x9b, 0x34, 0x68, 0xce, 0x8e, + 0xa8, 0xcb, 0xee, 0x6e, 0x6d, 0xcb, 0xe4, 0x8a, 0x89, 0xc4, 0x79, 0xda, 0x83, 0x12, 0xf3, 0xe8, + 0x00, 0x89, 0x39, 0xf1, 0xf3, 0xb1, 0xbe, 0x7e, 0xfe, 0x06, 0x8c, 0xfb, 0x69, 0x9d, 0x19, 0xcd, + 0x82, 0x3a, 0x8e, 0x27, 0x06, 0x3d, 0x8e, 0xac, 0x54, 0xcd, 0x26, 0xa4, 0x19, 0x2c, 0xc2, 0xa6, + 0x0e, 0xfb, 0xbd, 0x02, 0xa0, 0x9c, 0x93, 0xc8, 0xe4, 0x13, 0xa1, 0x77, 0x2c, 0x98, 0x0c, 0x4c, + 0xb0, 0xce, 0xaf, 0x27, 0x95, 0xe9, 0xd3, 0x0d, 0xcf, 0xe3, 0xf3, 0x3a, 0x51, 0x08, 0x13, 0x82, + 0x3b, 0x8d, 0x06, 0x75, 0x95, 0x55, 0x3a, 0xce, 0x1e, 0xbf, 0x85, 0x0d, 0xea, 0x6b, 0x8c, 0x72, + 0xea, 0x01, 0x5b, 0x06, 0xb7, 0x31, 0x9b, 0x36, 0xa0, 0x38, 0xa7, 0x01, 0xbd, 0x6d, 0xc1, 0xb4, + 0xac, 0xc2, 0x4c, 0x12, 0x3d, 0x6e, 0x7b, 0xe2, 0xf6, 0xd5, 0xe2, 0x2e, 0x09, 0x59, 0x53, 0xd3, + 0x8d, 0xc1, 0x3d, 0xda, 0xec, 0xbf, 0x5a, 0x30, 0xd3, 0x73, 0x22, 0x9d, 0xd3, 0x78, 0xad, 0xe1, + 0x43, 0x49, 0x96, 0x13, 0x49, 0x16, 0x5d, 0x3d, 0xd6, 0x59, 0x67, 0x85, 0x4c, 0x56, 0xfa, 0x48, + 0x58, 0x84, 0x63, 0x25, 0xf6, 0x02, 0x4c, 0xe6, 0x06, 0x26, 0x87, 0x4f, 0x11, 0xed, 0xf7, 0x4b, + 0x30, 0x9d, 0xc8, 0x8d, 0x36, 0x3b, 0xed, 0xb6, 0xc3, 0x4f, 0xa3, 0xf0, 0xff, 0xbe, 0x05, 0x67, + 0x4d, 0xc7, 0xa4, 0xe9, 0x16, 0x55, 0x8f, 0xb5, 0x45, 0xb1, 0x6f, 0x9c, 0xd7, 0xba, 0xcf, 0x6e, + 0xe4, 0x55, 0xe0, 0x6e, 0x9d, 0xe8, 0x37, 0x16, 0xdc, 0x1f, 0x6b, 0xd1, 0xaf, 0xbd, 0xba, 0x38, + 0xb4, 0xa3, 0x9e, 0x84, 0x51, 0xff, 0xaf, 0x8d, 0xba, 0x7f, 0xe9, 0x16, 0xfa, 0xf0, 0x2d, 0xad, + 0x41, 0xbf, 0xb0, 0xe0, 0xee, 0x98, 0xa0, 0xdb, 0xce, 0xe2, 0x89, 0xd9, 0x79, 0x41, 0xdb, 0x79, + 0xf7, 0xd2, 0x41, 0x8a, 0xf0, 0xc1, 0xfa, 0x65, 0x0b, 0xd3, 0x4e, 0x9a, 0x6c, 0x55, 0x2d, 0x1d, + 0xc1, 0x98, 0xde, 0x2e, 0x3d, 0x2b, 0x73, 0x52, 0x1c, 0xce, 0xf4, 0xd8, 0xaf, 0xc2, 0x5d, 0x75, + 0xa7, 0x49, 0x03, 0x55, 0x35, 0xaf, 0x12, 0xf1, 0x7c, 0x28, 0xff, 0x44, 0xf1, 0xa8, 0xaa, 0x19, + 0xbb, 0x7d, 0xc1, 0x1c, 0x55, 0x35, 0x09, 0x56, 0x18, 0xd9, 0xfd, 0xfb, 0xb4, 0x4d, 0x85, 0xae, + 0xea, 0xd3, 0x70, 0x5a, 0x93, 0x40, 0x1c, 0xe3, 0x6c, 0x07, 0x26, 0xcc, 0x0e, 0xfe, 0x4e, 0xcc, + 0xe4, 0x7f, 0x57, 0x80, 0x64, 0xda, 0x88, 0x1e, 0x35, 0x5a, 0xf7, 0x58, 0xc5, 0xec, 0xe1, 0x6d, + 0x3b, 0xda, 0xd0, 0x43, 0x83, 0xa1, 0x43, 0xe2, 0xb4, 0x23, 0xa8, 0x5f, 0x8e, 0x3f, 0x27, 0x2b, + 0xd7, 0x02, 0xf1, 0x3c, 0xdf, 0x14, 0x9c, 0x06, 0xcd, 0x78, 0x5c, 0x62, 0x8c, 0x18, 0xbe, 0x00, + 0x23, 0x24, 0x50, 0xf3, 0x08, 0x55, 0x20, 0x95, 0xe2, 0x89, 0xe8, 0x4a, 0x0c, 0xc2, 0x09, 0x4e, + 0xb6, 0xc4, 0xd4, 0x6d, 0x87, 0xb2, 0x48, 0x55, 0x45, 0x64, 0x29, 0x6e, 0x89, 0x6b, 0xcb, 0xeb, + 0x75, 0x55, 0xb8, 0xa6, 0xd8, 0x84, 0x72, 0x39, 0x99, 0x02, 0x1b, 0x94, 0x12, 0x86, 0x53, 0xac, + 0xa2, 0x6c, 0x6a, 0x99, 0xc3, 0x06, 0xe5, 0x6a, 0x2a, 0x53, 0x63, 0xd1, 0x15, 0xfd, 0x4a, 0x50, + 0x37, 0x31, 0xaa, 0xe4, 0x18, 0xeb, 0x7a, 0xab, 0x97, 0xcc, 0xa9, 0x72, 0x94, 0x72, 0x79, 0x11, + 0x77, 0xd5, 0xf2, 0x46, 0xb3, 0xe5, 0x6d, 0xc6, 0x20, 0x9c, 0xe0, 0x50, 0x19, 0x20, 0xe2, 0xae, + 0x5e, 0xb5, 0x2a, 0x2f, 0x4a, 0xd5, 0x29, 0x79, 0x9b, 0x6d, 0xa6, 0x50, 0x6c, 0x50, 0xd8, 0x04, + 0xa6, 0xbb, 0xdb, 0x8c, 0x3b, 0xe1, 0x2e, 0xef, 0x15, 0xe1, 0xfc, 0x66, 0x27, 0x94, 0x07, 0x15, + 0x7f, 0xb8, 0xb0, 0xcc, 0x7c, 0x5f, 0x57, 0xce, 0x77, 0xfe, 0xd2, 0x7e, 0x05, 0xc6, 0xc8, 0x8d, + 0x90, 0x72, 0xe2, 0x2d, 0x25, 0xfe, 0xf6, 0xa5, 0xdb, 0x53, 0xb1, 0x45, 0xdb, 0x24, 0x5b, 0xda, + 0x4a, 0x22, 0x04, 0x67, 0xf2, 0xe4, 0x5e, 0x44, 0x34, 0x70, 0x89, 0x24, 0xd5, 0x7d, 0x4b, 0xca, + 0xb0, 0x99, 0x20, 0x70, 0x46, 0x23, 0x7b, 0xc3, 0x46, 0xfa, 0xa9, 0x87, 0xf2, 0xc1, 0x23, 0xf4, + 0x86, 0xdd, 0x9f, 0x8c, 0x64, 0x3b, 0x90, 0xc1, 0xb0, 0xa1, 0x07, 0xfd, 0xd8, 0x82, 0x29, 0x27, + 0xff, 0xb5, 0x46, 0xfc, 0x6a, 0x63, 0xfd, 0x68, 0xaa, 0xfb, 0x7c, 0x79, 0x52, 0xbd, 0x47, 0xdb, + 0x31, 0xd5, 0xf5, 0xd9, 0x46, 0x97, 0x72, 0xfb, 0x53, 0x0b, 0xee, 0xeb, 0xe3, 0x11, 0xa7, 0x30, + 0xcf, 0xf1, 0xf3, 0xf3, 0x9c, 0x81, 0xcb, 0x9b, 0x3e, 0x96, 0xf7, 0x99, 0xec, 0xfc, 0x6c, 0x08, + 0x1e, 0xe8, 0xc3, 0x71, 0xe4, 0x19, 0xcf, 0x93, 0x30, 0x99, 0xfc, 0x37, 0xc3, 0x30, 0x2b, 0xa6, + 0x4d, 0x24, 0xce, 0xd3, 0x26, 0xaa, 0xd4, 0x85, 0x55, 0xe8, 0x55, 0x15, 0x5f, 0x5a, 0x09, 0x85, + 0xf4, 0x70, 0x97, 0xb5, 0x43, 0x9f, 0x08, 0x12, 0x37, 0xde, 0xa3, 0x99, 0x87, 0x2f, 0x27, 0x08, + 0x9c, 0xd1, 0xc8, 0x24, 0x45, 0x38, 0x67, 0x5c, 0x79, 0x98, 0x31, 0xa2, 0x5e, 0x91, 0x40, 0x1c, + 0xe3, 0xec, 0x7f, 0x5a, 0x70, 0xa1, 0xcf, 0xa6, 0x9c, 0x5a, 0x95, 0xbb, 0x93, 0xaf, 0x72, 0x5f, + 0x38, 0x21, 0x37, 0x38, 0xac, 0xde, 0xad, 0x6e, 0x7d, 0xf0, 0xf1, 0xdc, 0x99, 0x0f, 0x3f, 0x9e, + 0x3b, 0xf3, 0xd1, 0xc7, 0x73, 0x67, 0xde, 0xde, 0x9f, 0xb3, 0x3e, 0xd8, 0x9f, 0xb3, 0x3e, 0xdc, + 0x9f, 0xb3, 0x3e, 0xda, 0x9f, 0xb3, 0xfe, 0xbc, 0x3f, 0x67, 0xfd, 0xf4, 0x2f, 0x73, 0x67, 0x5e, + 0x2e, 0x0f, 0xf6, 0x65, 0xfb, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x70, 0x2b, 0xff, 0xf0, 0x0a, + 0x2f, 0x00, 0x00, } func (m *AddressGroup) Marshal() (dAtA []byte, err error) { @@ -3279,6 +3282,16 @@ func (m *Service) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.SrcEndPort != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.SrcEndPort)) + i-- + dAtA[i] = 0x48 + } + if m.SrcPort != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.SrcPort)) + i-- + dAtA[i] = 0x40 + } i -= len(m.GroupAddress) copy(dAtA[i:], m.GroupAddress) i = encodeVarintGenerated(dAtA, i, uint64(len(m.GroupAddress))) @@ -4305,6 +4318,12 @@ func (m *Service) Size() (n int) { } l = len(m.GroupAddress) n += 1 + l + sovGenerated(uint64(l)) + if m.SrcPort != nil { + n += 1 + sovGenerated(uint64(*m.SrcPort)) + } + if m.SrcEndPort != nil { + n += 1 + sovGenerated(uint64(*m.SrcEndPort)) + } return n } @@ -4996,6 +5015,8 @@ func (this *Service) String() string { `ICMPCode:` + valueToStringGenerated(this.ICMPCode) + `,`, `IGMPType:` + valueToStringGenerated(this.IGMPType) + `,`, `GroupAddress:` + fmt.Sprintf("%v", this.GroupAddress) + `,`, + `SrcPort:` + valueToStringGenerated(this.SrcPort) + `,`, + `SrcEndPort:` + valueToStringGenerated(this.SrcEndPort) + `,`, `}`, }, "") return s @@ -10498,6 +10519,46 @@ func (m *Service) Unmarshal(dAtA []byte) error { } m.GroupAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SrcPort", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SrcPort = &v + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SrcEndPort", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SrcEndPort = &v default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/pkg/apis/controlplane/v1beta2/generated.proto b/pkg/apis/controlplane/v1beta2/generated.proto index fdd2465afd1..03fd0e6fbab 100644 --- a/pkg/apis/controlplane/v1beta2/generated.proto +++ b/pkg/apis/controlplane/v1beta2/generated.proto @@ -459,6 +459,13 @@ message Service { optional int32 igmpType = 6; optional string groupAddress = 7; + + // SrcPort and SrcEndPort can only be specified, when the Protocol is TCP, UDP, or SCTP. + // It restricts the source port of the traffic. + // +optional + optional int32 srcPort = 8; + + optional int32 srcEndPort = 9; } // ServiceReference represents reference to a v1.Service. diff --git a/pkg/apis/controlplane/v1beta2/types.go b/pkg/apis/controlplane/v1beta2/types.go index ae8d4fae99d..da8c7bf0902 100644 --- a/pkg/apis/controlplane/v1beta2/types.go +++ b/pkg/apis/controlplane/v1beta2/types.go @@ -300,6 +300,11 @@ type Service struct { // +optional IGMPType *int32 `json:"igmpType,omitempty" protobuf:"varint,6,opt,name=igmpType"` GroupAddress string `json:"groupAddress,omitempty" protobuf:"bytes,7,opt,name=groupAddress"` + // SrcPort and SrcEndPort can only be specified, when the Protocol is TCP, UDP, or SCTP. + // It restricts the source port of the traffic. + // +optional + SrcPort *int32 `json:"srcPort,omitempty" protobuf:"bytes,8,opt,name=srcPort"` + SrcEndPort *int32 `json:"srcEndPort,omitempty" protobuf:"bytes,9,opt,name=srcEndPort"` } // L7Protocol defines application layer protocol to match. diff --git a/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go b/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go index 5caf72fc736..2e3d272aaf7 100644 --- a/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go +++ b/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go @@ -1465,7 +1465,17 @@ func autoConvert_v1beta2_NetworkPolicyRule_To_controlplane_NetworkPolicyRule(in if err := Convert_v1beta2_NetworkPolicyPeer_To_controlplane_NetworkPolicyPeer(&in.To, &out.To, s); err != nil { return err } - out.Services = *(*[]controlplane.Service)(unsafe.Pointer(&in.Services)) + if in.Services != nil { + in, out := &in.Services, &out.Services + *out = make([]controlplane.Service, len(*in)) + for i := range *in { + if err := Convert_v1beta2_Service_To_controlplane_Service(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Services = nil + } out.Priority = in.Priority out.Action = (*v1alpha1.RuleAction)(unsafe.Pointer(in.Action)) out.EnableLogging = in.EnableLogging @@ -1488,7 +1498,17 @@ func autoConvert_controlplane_NetworkPolicyRule_To_v1beta2_NetworkPolicyRule(in if err := Convert_controlplane_NetworkPolicyPeer_To_v1beta2_NetworkPolicyPeer(&in.To, &out.To, s); err != nil { return err } - out.Services = *(*[]Service)(unsafe.Pointer(&in.Services)) + if in.Services != nil { + in, out := &in.Services, &out.Services + *out = make([]Service, len(*in)) + for i := range *in { + if err := Convert_controlplane_Service_To_v1beta2_Service(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Services = nil + } out.Name = in.Name out.Priority = in.Priority out.Action = (*v1alpha1.RuleAction)(unsafe.Pointer(in.Action)) @@ -1678,6 +1698,8 @@ func autoConvert_v1beta2_Service_To_controlplane_Service(in *Service, out *contr out.ICMPCode = (*int32)(unsafe.Pointer(in.ICMPCode)) out.IGMPType = (*int32)(unsafe.Pointer(in.IGMPType)) out.GroupAddress = in.GroupAddress + out.SrcPort = (*int32)(unsafe.Pointer(in.SrcPort)) + out.SrcEndPort = (*int32)(unsafe.Pointer(in.SrcEndPort)) return nil } @@ -1690,6 +1712,8 @@ func autoConvert_controlplane_Service_To_v1beta2_Service(in *controlplane.Servic out.Protocol = (*Protocol)(unsafe.Pointer(in.Protocol)) out.Port = (*intstr.IntOrString)(unsafe.Pointer(in.Port)) out.EndPort = (*int32)(unsafe.Pointer(in.EndPort)) + out.SrcPort = (*int32)(unsafe.Pointer(in.SrcPort)) + out.SrcEndPort = (*int32)(unsafe.Pointer(in.SrcEndPort)) out.ICMPType = (*int32)(unsafe.Pointer(in.ICMPType)) out.ICMPCode = (*int32)(unsafe.Pointer(in.ICMPCode)) out.IGMPType = (*int32)(unsafe.Pointer(in.IGMPType)) diff --git a/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go b/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go index d0f0e688b50..0e70afea3f5 100644 --- a/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go +++ b/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go @@ -1123,6 +1123,16 @@ func (in *Service) DeepCopyInto(out *Service) { *out = new(int32) **out = **in } + if in.SrcPort != nil { + in, out := &in.SrcPort, &out.SrcPort + *out = new(int32) + **out = **in + } + if in.SrcEndPort != nil { + in, out := &in.SrcEndPort, &out.SrcEndPort + *out = new(int32) + **out = **in + } return } diff --git a/pkg/apis/controlplane/zz_generated.deepcopy.go b/pkg/apis/controlplane/zz_generated.deepcopy.go index e6dcddcd12d..187e4056a5f 100644 --- a/pkg/apis/controlplane/zz_generated.deepcopy.go +++ b/pkg/apis/controlplane/zz_generated.deepcopy.go @@ -1108,6 +1108,16 @@ func (in *Service) DeepCopyInto(out *Service) { *out = new(int32) **out = **in } + if in.SrcPort != nil { + in, out := &in.SrcPort, &out.SrcPort + *out = new(int32) + **out = **in + } + if in.SrcEndPort != nil { + in, out := &in.SrcEndPort, &out.SrcEndPort + *out = new(int32) + **out = **in + } if in.ICMPType != nil { in, out := &in.ICMPType, &out.ICMPType *out = new(int32) diff --git a/pkg/apis/crd/v1alpha1/types.go b/pkg/apis/crd/v1alpha1/types.go index a3c174fd1c9..08d63a8db80 100644 --- a/pkg/apis/crd/v1alpha1/types.go +++ b/pkg/apis/crd/v1alpha1/types.go @@ -581,10 +581,18 @@ type NetworkPolicyPort struct { // matches all port names and numbers. // +optional Port *intstr.IntOrString `json:"port,omitempty"` - // EndPort defines the end of the port range, being the end included within the range. + // EndPort defines the end of the port range, inclusive. // It can only be specified when a numerical `port` is specified. // +optional EndPort *int32 `json:"endPort,omitempty"` + // The source port on the given protocol. This can only be a numerical port. + // If this field is not provided, rule matches all source ports. + // +optional + SourcePort *int32 `json:"sourcePort,omitempty"` + // SourceEndPort defines the end of the source port range, inclusive. + // It can only be specified when `sourcePort` is specified. + // +optional + SourceEndPort *int32 `json:"sourceEndPort,omitempty"` } // RuleAction describes the action to be applied on traffic matching a rule. @@ -595,9 +603,9 @@ const ( RuleActionAllow RuleAction = "Allow" // RuleActionDrop describes that the traffic matching the rule must be dropped. RuleActionDrop RuleAction = "Drop" - // RuleActionPass indicates that the traffic matching the rule will not be evalutated + // RuleActionPass indicates that the traffic matching the rule will not be evaluated // by Antrea NetworkPolicy or ClusterNetworkPolicy, but rather punt to K8s namespaced - // NetworkPolicy for evaluaion. + // NetworkPolicy for evaluation. RuleActionPass RuleAction = "Pass" // RuleActionReject indicates that the traffic matching the rule must be rejected and the // client will receive a response. diff --git a/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go index 064ade764eb..5d637d04d43 100644 --- a/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated // +build !ignore_autogenerated -// Copyright 2022 Antrea Authors +// Copyright 2023 Antrea Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -690,6 +690,16 @@ func (in *NetworkPolicyPort) DeepCopyInto(out *NetworkPolicyPort) { *out = new(int32) **out = **in } + if in.SourcePort != nil { + in, out := &in.SourcePort, &out.SourcePort + *out = new(int32) + **out = **in + } + if in.SourceEndPort != nil { + in, out := &in.SourceEndPort, &out.SourceEndPort + *out = new(int32) + **out = **in + } return } diff --git a/pkg/apiserver/openapi/zz_generated.openapi.go b/pkg/apiserver/openapi/zz_generated.openapi.go index 0bf905fa034..bc83210517d 100644 --- a/pkg/apiserver/openapi/zz_generated.openapi.go +++ b/pkg/apiserver/openapi/zz_generated.openapi.go @@ -2134,6 +2134,19 @@ func schema_pkg_apis_controlplane_v1beta2_Service(ref common.ReferenceCallback) Format: "", }, }, + "srcPort": { + SchemaProps: spec.SchemaProps{ + Description: "SrcPort and SrcEndPort can only be specified, when the Protocol is TCP, UDP, or SCTP. It restricts the source port of the traffic.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "srcEndPort": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, }, }, }, diff --git a/pkg/controller/networkpolicy/crd_utils.go b/pkg/controller/networkpolicy/crd_utils.go index 51eacd5db6f..28a703c6532 100644 --- a/pkg/controller/networkpolicy/crd_utils.go +++ b/pkg/controller/networkpolicy/crd_utils.go @@ -84,9 +84,11 @@ func toAntreaServicesForCRD(npPorts []v1alpha1.NetworkPolicyPort, npProtocols [] namedPortExists = true } antreaServices = append(antreaServices, controlplane.Service{ - Protocol: toAntreaProtocol(npPort.Protocol), - Port: npPort.Port, - EndPort: npPort.EndPort, + Protocol: toAntreaProtocol(npPort.Protocol), + Port: npPort.Port, + EndPort: npPort.EndPort, + SrcPort: npPort.SourcePort, + SrcEndPort: npPort.SourceEndPort, }) } for _, npProtocol := range npProtocols { diff --git a/pkg/controller/networkpolicy/networkpolicy_controller_test.go b/pkg/controller/networkpolicy/networkpolicy_controller_test.go index a5ac1b77c4c..67ae6b4f46a 100644 --- a/pkg/controller/networkpolicy/networkpolicy_controller_test.go +++ b/pkg/controller/networkpolicy/networkpolicy_controller_test.go @@ -75,7 +75,9 @@ var ( int81 = intstr.FromInt(81) int1000 = intstr.FromInt(1000) - int32For1999 = int32(1999) + int32For1999 = int32(1999) + int32For32220 = int32(32220) + int32For32230 = int32(32230) strHTTP = intstr.FromString("http") ) diff --git a/pkg/controller/networkpolicy/validate.go b/pkg/controller/networkpolicy/validate.go index a76a4188de7..4f92822dcd9 100644 --- a/pkg/controller/networkpolicy/validate.go +++ b/pkg/controller/networkpolicy/validate.go @@ -285,17 +285,24 @@ func (v *antreaPolicyValidator) validatePort(ingress, egress []crdv1alpha1.Rule) isValid := func(rules []crdv1alpha1.Rule) error { for _, rule := range rules { for _, port := range rule.Ports { - if port.EndPort == nil { - continue + if port.EndPort != nil { + if port.Port == nil { + return fmt.Errorf("if `endPort` is specified `port` must be specified") + } + if port.Port.Type == intstr.String { + return fmt.Errorf("if `port` is a string `endPort` cannot be specified") + } + if *port.EndPort < port.Port.IntVal { + return fmt.Errorf("`endPort` should be greater than or equal to `port`") + } } - if port.Port == nil { - return fmt.Errorf("if `endPort` is specified `port` must be specified") - } - if port.Port.Type == intstr.String { - return fmt.Errorf("if `port` is a string `endPort` cannot be specified") - } - if *port.EndPort < port.Port.IntVal { - return fmt.Errorf("`endPort` should be greater than or equal to `port`") + if port.SourceEndPort != nil { + if port.SourcePort == nil { + return fmt.Errorf("if `sourceEndPort` is specified `sourcePort` must be specified") + } + if *port.SourceEndPort < *port.SourcePort { + return fmt.Errorf("`sourceEndPort` should be greater than or equal to `sourcePort`") + } } } } diff --git a/pkg/controller/networkpolicy/validate_test.go b/pkg/controller/networkpolicy/validate_test.go index dcddd52f23c..a12b76e2727 100644 --- a/pkg/controller/networkpolicy/validate_test.go +++ b/pkg/controller/networkpolicy/validate_test.go @@ -893,6 +893,34 @@ func TestValidateAntreaPolicy(t *testing.T) { }, expectedReason: "if `endPort` is specified `port` must be specified", }, + { + name: "acnp-sourceendport-without-sourceport-in-ports", + policy: &crdv1alpha1.ClusterNetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "acnp-sourceendport-without-port-in-ports", + }, + Spec: crdv1alpha1.ClusterNetworkPolicySpec{ + AppliedTo: []crdv1alpha1.AppliedTo{ + { + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"foo1": "bar1"}, + }, + }, + }, + Ingress: []crdv1alpha1.Rule{ + { + Action: &allowAction, + Ports: []crdv1alpha1.NetworkPolicyPort{ + { + SourceEndPort: &int32For32230, + }, + }, + }, + }, + }, + }, + expectedReason: "if `sourceEndPort` is specified `sourcePort` must be specified", + }, { name: "acnp-endport-smaller-port-in-ports", policy: &crdv1alpha1.ClusterNetworkPolicy{ @@ -922,6 +950,35 @@ func TestValidateAntreaPolicy(t *testing.T) { }, expectedReason: "`endPort` should be greater than or equal to `port`", }, + { + name: "acnp-sourceendport-smaller-sourceport-in-ports", + policy: &crdv1alpha1.ClusterNetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "acnp-sourceendport-smaller-port-in-ports", + }, + Spec: crdv1alpha1.ClusterNetworkPolicySpec{ + AppliedTo: []crdv1alpha1.AppliedTo{ + { + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"foo1": "bar1"}, + }, + }, + }, + Ingress: []crdv1alpha1.Rule{ + { + Action: &allowAction, + Ports: []crdv1alpha1.NetworkPolicyPort{ + { + SourcePort: &int32For32230, + SourceEndPort: &int32For32220, + }, + }, + }, + }, + }, + }, + expectedReason: "`sourceEndPort` should be greater than or equal to `sourcePort`", + }, { name: "acnp-named-port-with-endport-in-ports", policy: &crdv1alpha1.ClusterNetworkPolicy{ diff --git a/test/e2e/antreapolicy_test.go b/test/e2e/antreapolicy_test.go index 915c334870e..1aede8c560e 100644 --- a/test/e2e/antreapolicy_test.go +++ b/test/e2e/antreapolicy_test.go @@ -568,6 +568,77 @@ func testACNPAllowXBtoA(t *testing.T) { executeTests(t, testCase) } +// testACNPSourcePort tests ACNP source port filtering. The agnhost image used in E2E tests uses +// ephemeral ports to initiate TCP connections, which should be 32768–60999 by default +// (https://en.wikipedia.org/wiki/Ephemeral_port). This test retrieves the port range from +// the client Pod and uses it in sourcePort and sourceEndPort of an ACNP rule to verify that +// packets can be matched by source port. +func testACNPSourcePort(t *testing.T) { + portStart, portEnd, err := k8sUtils.getTCPv4SourcePortRangeFromPod(namespaces["x"], "a") + failOnError(err, t) + builder := &ClusterNetworkPolicySpecBuilder{} + builder = builder.SetName("acnp-source-port"). + SetPriority(1.0). + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) + builder.AddIngressForSrcPort(ProtocolTCP, nil, nil, &portStart, &portEnd, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, + nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) + + builder2 := &ClusterNetworkPolicySpecBuilder{} + builder2 = builder2.SetName("acnp-source-port"). + SetPriority(1.0). + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) + builder2.AddIngressForSrcPort(ProtocolTCP, &p80, nil, &portStart, &portEnd, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, + nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) + + builder3 := &ClusterNetworkPolicySpecBuilder{} + builder3 = builder3.SetName("acnp-source-port"). + SetPriority(1.0). + SetAppliedToGroup([]ACNPAppliedToSpec{{PodSelector: map[string]string{"pod": "a"}}}) + builder3.AddIngressForSrcPort(ProtocolTCP, &p80, &p81, &portStart, &portEnd, nil, nil, nil, nil, nil, map[string]string{"pod": "b"}, map[string]string{"ns": namespaces["x"]}, + nil, nil, false, nil, crdv1alpha1.RuleActionDrop, "", "", nil) + + reachability := NewReachability(allPods, Connected) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["x"]+"/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["y"]+"/a"), Dropped) + reachability.Expect(Pod(namespaces["x"]+"/b"), Pod(namespaces["z"]+"/a"), Dropped) + // After adding the dst port constraint of port 80, traffic on port 81 should not be affected. + updatedReachability := NewReachability(allPods, Connected) + + testSteps := []*TestStep{ + { + "Port 80", + reachability, + []metav1.Object{builder.Get()}, + []int32{80}, + ProtocolTCP, + 0, + nil, + }, + { + "Port 81", + updatedReachability, + []metav1.Object{builder2.Get()}, + []int32{81}, + ProtocolTCP, + 0, + nil, + }, + { + "Port range 80-81", + reachability, + []metav1.Object{builder3.Get()}, + []int32{80, 81}, + ProtocolTCP, + 0, + nil, + }, + } + testCase := []*TestCase{ + {"ACNP Drop X/B to A based on source port", testSteps}, + } + executeTests(t, testCase) +} + // testACNPAllowXBtoYA tests traffic from X/B to Y/A on named port 81, after applying the default deny // k8s NetworkPolicies in all namespaces and ACNP to allow X/B to Y/A. func testACNPAllowXBtoYA(t *testing.T) { @@ -4325,6 +4396,7 @@ func TestAntreaPolicy(t *testing.T) { t.Run("Case=ACNPDropEgressSCTP", func(t *testing.T) { testACNPDropEgress(t, ProtocolSCTP) }) t.Run("Case=ACNPDropIngressInNamespace", func(t *testing.T) { testACNPDropIngressInSelectedNamespace(t) }) t.Run("Case=ACNPPortRange", func(t *testing.T) { testACNPPortRange(t) }) + t.Run("Case=ACNPSourcePort", func(t *testing.T) { testACNPSourcePort(t) }) t.Run("Case=ACNPRejectEgress", func(t *testing.T) { testACNPRejectEgress(t) }) t.Run("Case=ACNPRejectIngress", func(t *testing.T) { testACNPRejectIngress(t, ProtocolTCP) }) t.Run("Case=ACNPRejectIngressUDP", func(t *testing.T) { testACNPRejectIngress(t, ProtocolUDP) }) diff --git a/test/e2e/k8s_util.go b/test/e2e/k8s_util.go index d5ed2689f59..f3c20794a00 100644 --- a/test/e2e/k8s_util.go +++ b/test/e2e/k8s_util.go @@ -17,6 +17,7 @@ package e2e import ( "context" "fmt" + "strconv" "strings" "sync" "testing" @@ -131,6 +132,31 @@ func (k *KubernetesUtils) LabelPod(ns, name, key, value string) (*v1.Pod, error) return k.clientset.CoreV1().Pods(ns).Update(context.TODO(), pod, metav1.UpdateOptions{}) } +func (k *KubernetesUtils) getTCPv4SourcePortRangeFromPod(podNamespace, podNameLabel string) (int32, int32, error) { + pod, err := k.GetPodByLabel(podNamespace, podNameLabel) + if err != nil { + return 0, 0, err + } + cmd := []string{ + "/bin/sh", + "-c", + "cat /proc/sys/net/ipv4/ip_local_port_range", + } + stdout, stderr, err := k.RunCommandFromPod(pod.Namespace, pod.Name, "c80", cmd) + if err != nil || stderr != "" { + log.Errorf("Failed to retrieve TCP source port range for Pod %s/%s", podNamespace, podNameLabel) + return 0, 0, err + } + ports := strings.Fields(stdout) + if len(ports) < 2 { + log.Errorf("Failed to retrieve TCP source port range for Pod %s/%s", podNamespace, podNameLabel) + return 0, 0, err + } + startPort, _ := strconv.ParseInt(ports[0], 0, 32) + endPort, _ := strconv.ParseInt(ports[1], 0, 32) + return int32(startPort), int32(endPort), nil +} + func (k *KubernetesUtils) probe( pod *v1.Pod, podName string, diff --git a/test/e2e/utils/anp_spec_builder.go b/test/e2e/utils/anp_spec_builder.go index 42645991e43..26abcac55fc 100644 --- a/test/e2e/utils/anp_spec_builder.go +++ b/test/e2e/utils/anp_spec_builder.go @@ -151,7 +151,7 @@ func (b *AntreaNetworkPolicySpecBuilder) AddIngress(protoc AntreaPolicyProtocol, Group: ruleGroup, }} } - ports, protocols := GenPortsOrProtocols(protoc, port, portName, endPort, icmpType, icmpCode, igmpType, groupAddress) + ports, protocols := GenPortsOrProtocols(protoc, port, portName, endPort, nil, nil, icmpType, icmpCode, igmpType, groupAddress) newRule := crdv1alpha1.Rule{ From: policyPeer, Ports: ports, diff --git a/test/e2e/utils/cnp_spec_builder.go b/test/e2e/utils/cnp_spec_builder.go index 761e2f9e0c4..f4d2e5aef5e 100644 --- a/test/e2e/utils/cnp_spec_builder.go +++ b/test/e2e/utils/cnp_spec_builder.go @@ -162,7 +162,77 @@ func (b *ClusterNetworkPolicySpecBuilder) AddIngress(protoc AntreaPolicyProtocol ServiceAccount: serviceAccount, }} } - ports, protocols := GenPortsOrProtocols(protoc, port, portName, endPort, icmpType, icmpCode, igmpType, groupAddress) + ports, protocols := GenPortsOrProtocols(protoc, port, portName, endPort, nil, nil, icmpType, icmpCode, igmpType, groupAddress) + newRule := crdv1alpha1.Rule{ + From: policyPeer, + Ports: ports, + Protocols: protocols, + Action: &action, + Name: name, + AppliedTo: appliedTos, + } + b.Spec.Ingress = append(b.Spec.Ingress, newRule) + return b +} + +// TODO: added new function to avoid merge conflicts. Unify this function with 'addIngress' when +// +// all conflicting PRs are merged. +func (b *ClusterNetworkPolicySpecBuilder) AddIngressForSrcPort(protoc AntreaPolicyProtocol, + port, endPort, srcPort, endSrcPort, icmpType, icmpCode, igmpType *int32, + groupAddress, cidr *string, podSelector map[string]string, nsSelector map[string]string, + podSelectorMatchExp []metav1.LabelSelectorRequirement, nsSelectorMatchExp []metav1.LabelSelectorRequirement, selfNS bool, + ruleAppliedToSpecs []ACNPAppliedToSpec, action crdv1alpha1.RuleAction, ruleClusterGroup, name string, serviceAccount *crdv1alpha1.NamespacedName) *ClusterNetworkPolicySpecBuilder { + + var pSel *metav1.LabelSelector + var nSel *metav1.LabelSelector + var ns *crdv1alpha1.PeerNamespaces + var appliedTos []crdv1alpha1.AppliedTo + matchSelf := crdv1alpha1.NamespaceMatchSelf + + if b.Spec.Ingress == nil { + b.Spec.Ingress = []crdv1alpha1.Rule{} + } + + if podSelector != nil || podSelectorMatchExp != nil { + pSel = &metav1.LabelSelector{ + MatchLabels: podSelector, + MatchExpressions: podSelectorMatchExp, + } + } + if nsSelector != nil || nsSelectorMatchExp != nil { + nSel = &metav1.LabelSelector{ + MatchLabels: nsSelector, + MatchExpressions: nsSelectorMatchExp, + } + } + if selfNS == true { + ns = &crdv1alpha1.PeerNamespaces{ + Match: matchSelf, + } + } + var ipBlock *crdv1alpha1.IPBlock + if cidr != nil { + ipBlock = &crdv1alpha1.IPBlock{ + CIDR: *cidr, + } + } + for _, at := range ruleAppliedToSpecs { + appliedTos = append(appliedTos, b.GetAppliedToPeer(at.PodSelector, at.NSSelector, at.PodSelectorMatchExp, at.NSSelectorMatchExp, at.Group, at.Service)) + } + // An empty From/To in ACNP rules evaluates to match all addresses. + policyPeer := make([]crdv1alpha1.NetworkPolicyPeer, 0) + if pSel != nil || nSel != nil || ns != nil || ipBlock != nil || ruleClusterGroup != "" || serviceAccount != nil { + policyPeer = []crdv1alpha1.NetworkPolicyPeer{{ + PodSelector: pSel, + NamespaceSelector: nSel, + Namespaces: ns, + IPBlock: ipBlock, + Group: ruleClusterGroup, + ServiceAccount: serviceAccount, + }} + } + ports, protocols := GenPortsOrProtocols(protoc, port, nil, endPort, srcPort, endSrcPort, icmpType, icmpCode, igmpType, groupAddress) newRule := crdv1alpha1.Rule{ From: policyPeer, Ports: ports, @@ -232,7 +302,7 @@ func (b *ClusterNetworkPolicySpecBuilder) AddFQDNRule(fqdn string, appliedTos = append(appliedTos, b.GetAppliedToPeer(at.PodSelector, at.NSSelector, at.PodSelectorMatchExp, at.NSSelectorMatchExp, at.Group, at.Service)) } policyPeer := []crdv1alpha1.NetworkPolicyPeer{{FQDN: fqdn}} - ports, _ := GenPortsOrProtocols(protoc, port, portName, endPort, nil, nil, nil, nil) + ports, _ := GenPortsOrProtocols(protoc, port, portName, endPort, nil, nil, nil, nil, nil, nil) newRule := crdv1alpha1.Rule{ To: policyPeer, Ports: ports, diff --git a/test/e2e/utils/helper.go b/test/e2e/utils/helper.go index a3ec1b8d7bb..fafa13d4a68 100644 --- a/test/e2e/utils/helper.go +++ b/test/e2e/utils/helper.go @@ -46,7 +46,7 @@ func AntreaPolicyProtocolToK8sProtocol(antreaProtocol AntreaPolicyProtocol) (v1. } } -func GenPortsOrProtocols(protoc AntreaPolicyProtocol, port *int32, portName *string, endPort, icmpType, icmpCode, igmpType *int32, groupAddress *string) ([]crdv1alpha1.NetworkPolicyPort, []crdv1alpha1.NetworkPolicyProtocol) { +func GenPortsOrProtocols(protoc AntreaPolicyProtocol, port *int32, portName *string, endPort, srcPort, srcEndPort, icmpType, icmpCode, igmpType *int32, groupAddress *string) ([]crdv1alpha1.NetworkPolicyPort, []crdv1alpha1.NetworkPolicyProtocol) { if protoc == ProtocolICMP { return nil, []crdv1alpha1.NetworkPolicyProtocol{ { @@ -80,16 +80,18 @@ func GenPortsOrProtocols(protoc AntreaPolicyProtocol, port *int32, portName *str }, } } - if port != nil || endPort != nil { + if port != nil || endPort != nil || srcPort != nil || srcEndPort != nil { var pVal *intstr.IntOrString if port != nil { pVal = &intstr.IntOrString{IntVal: *port} } ports = []crdv1alpha1.NetworkPolicyPort{ { - Port: pVal, - EndPort: endPort, - Protocol: &k8sProtocol, + Port: pVal, + EndPort: endPort, + SourcePort: srcPort, + SourceEndPort: srcEndPort, + Protocol: &k8sProtocol, }, } } diff --git a/test/e2e/vmagent_test.go b/test/e2e/vmagent_test.go index cd2ab2d8fd9..b03ae55cdd1 100644 --- a/test/e2e/vmagent_test.go +++ b/test/e2e/vmagent_test.go @@ -632,7 +632,7 @@ func createANPWithFQDN(t *testing.T, data *TestData, name string, namespace stri for fqdn, action := range fqdnSettings { ruleName := fmt.Sprintf("name-%d", i) policyPeer := []crdv1alpha1.NetworkPolicyPeer{{FQDN: fqdn}} - ports, _ := GenPortsOrProtocols(ProtocolTCP, nil, nil, nil, nil, nil, nil, nil) + ports, _ := GenPortsOrProtocols(ProtocolTCP, nil, nil, nil, nil, nil, nil, nil, nil, nil) newRule := crdv1alpha1.Rule{ To: policyPeer, Ports: ports,