// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package api

import (
	"github.com/cilium/cilium/pkg/slices"
)

// IngressCommonRule is a rule that shares some of its fields across the
// IngressRule and IngressDenyRule. It's publicly exported so the code
// generators can generate code for this structure.
//
// +deepequal-gen:private-method=true
type IngressCommonRule struct {
	// FromEndpoints is a list of endpoints identified by an
	// EndpointSelector which are allowed to communicate with the endpoint
	// subject to the rule.
	//
	// Example:
	// Any endpoint with the label "role=backend" can be consumed by any
	// endpoint carrying the label "role=frontend".
	//
	// Note that while an empty non-nil FromEndpoints does not select anything,
	// nil FromEndpoints is implicitly treated as a wildcard selector if ToPorts
	// are also specified.
	// To select everything, use one EndpointSelector without any match requirements.
	//
	// +kubebuilder:validation:Optional
	FromEndpoints []EndpointSelector `json:"fromEndpoints,omitempty"`

	// Deprecated.
	//
	// +kubebuilder:validation:MaxItems=0
	FromRequires []string `json:"fromRequires,omitempty"`

	// FromCIDR is a list of IP blocks which the endpoint subject to the
	// rule is allowed to receive connections from. Only connections which
	// do *not* originate from the cluster or from the local host are subject
	// to CIDR rules. In order to allow in-cluster connectivity, use the
	// FromEndpoints field.  This will match on the source IP address of
	// incoming connections. Adding  a prefix into FromCIDR or into
	// FromCIDRSet with no ExcludeCIDRs is  equivalent.  Overlaps are
	// allowed between FromCIDR and FromCIDRSet.
	//
	// Example:
	// Any endpoint with the label "app=my-legacy-pet" is allowed to receive
	// connections from 10.3.9.1
	//
	// +kubebuilder:validation:Optional
	FromCIDR CIDRSlice `json:"fromCIDR,omitempty"`

	// FromCIDRSet is a list of IP blocks which the endpoint subject to the
	// rule is allowed to receive connections from in addition to FromEndpoints,
	// along with a list of subnets contained within their corresponding IP block
	// from which traffic should not be allowed.
	// This will match on the source IP address of incoming connections. Adding
	// a prefix into FromCIDR or into FromCIDRSet with no ExcludeCIDRs is
	// equivalent. Overlaps are allowed between FromCIDR and FromCIDRSet.
	//
	// Example:
	// Any endpoint with the label "app=my-legacy-pet" is allowed to receive
	// connections from 10.0.0.0/8 except from IPs in subnet 10.96.0.0/12.
	//
	// +kubebuilder:validation:Optional
	FromCIDRSet CIDRRuleSlice `json:"fromCIDRSet,omitzero"`

	// FromEntities is a list of special entities which the endpoint subject
	// to the rule is allowed to receive connections from. Supported entities are
	// `world`, `cluster`, `host`, `remote-node`, `kube-apiserver`, `ingress`, `init`,
	// `health`, `unmanaged`, `none` and `all`.
	//
	// +kubebuilder:validation:Optional
	FromEntities EntitySlice `json:"fromEntities,omitempty"`

	// FromGroups allows policies to reference CIDRs provided by external integrations.
	// Currently, only AWS is supported, and the rule can select by multiple sub directives.
	// FromGroups entries are functionally equivalent to FromCIDR, and have the same
	// limitiations. They cannot select traffic originating from within the cluster.
	//
	//
	// Example:
	// fromGroups:
	// - aws:
	//     securityGroupsIds:
	//     - 'sg-XXXXXXXXXXXXX'
	//
	// +kubebuilder:validation:Optional
	FromGroups []Groups `json:"fromGroups,omitempty"`

	// FromNodes is a list of nodes identified by an
	// EndpointSelector which are allowed to communicate with the endpoint
	// subject to the rule.
	//
	// +kubebuilder:validation:Optional
	FromNodes []EndpointSelector `json:"fromNodes,omitempty"`
}

// DeepEqual returns true if both IngressCommonRule are deep equal.
// The semantic of a nil slice in one of its fields is different from the semantic
// of an empty non-nil slice, thus it explicitly checks for that case before calling
// the autogenerated method.
func (in *IngressCommonRule) DeepEqual(other *IngressCommonRule) bool {
	if slices.XorNil(in.FromEndpoints, other.FromEndpoints) {
		return false
	}
	if slices.XorNil(in.FromCIDR, other.FromCIDR) {
		return false
	}
	if slices.XorNil(in.FromCIDRSet, other.FromCIDRSet) {
		return false
	}
	if slices.XorNil(in.FromEntities, other.FromEntities) {
		return false
	}

	return in.deepEqual(other)
}

// IngressRule contains all rule types which can be applied at ingress,
// i.e. network traffic that originates outside of the endpoint and
// is entering the endpoint selected by the endpointSelector.
//
//   - All members of this structure are optional. If omitted or empty, the
//     member will have no effect on the rule.
//
//   - If multiple members are set, all of them need to match in order for
//     the rule to take effect.
//
//   - FromEndpoints, FromCIDR, FromCIDRSet and FromEntities are mutually
//     exclusive. Only one of these members may be present within an individual
//     rule.
type IngressRule struct {
	IngressCommonRule `json:",inline"`

	// ToPorts is a list of destination ports identified by port number and
	// protocol which the endpoint subject to the rule is allowed to
	// receive connections on.
	//
	// Example:
	// Any endpoint with the label "app=httpd" can only accept incoming
	// connections on port 80/tcp.
	//
	// +kubebuilder:validation:Optional
	ToPorts PortRules `json:"toPorts,omitempty"`

	// ICMPs is a list of ICMP rule identified by type number
	// which the endpoint subject to the rule is allowed to
	// receive connections on.
	//
	// Example:
	// Any endpoint with the label "app=httpd" can only accept incoming
	// type 8 ICMP connections.
	//
	// +kubebuilder:validation:Optional
	ICMPs ICMPRules `json:"icmps,omitempty"`

	// Authentication is the required authentication type for the allowed traffic, if any.
	//
	// +kubebuilder:validation:Optional
	Authentication *Authentication `json:"authentication,omitempty"`
}

// IngressDenyRule contains all rule types which can be applied at ingress,
// i.e. network traffic that originates outside of the endpoint and
// is entering the endpoint selected by the endpointSelector.
//
//   - All members of this structure are optional. If omitted or empty, the
//     member will have no effect on the rule.
//
//   - If multiple members are set, all of them need to match in order for
//     the rule to take effect.
//
//   - FromEndpoints, FromCIDR, FromCIDRSet, FromGroups and FromEntities are mutually
//     exclusive. Only one of these members may be present within an individual
//     rule.
type IngressDenyRule struct {
	IngressCommonRule `json:",inline"`

	// ToPorts is a list of destination ports identified by port number and
	// protocol which the endpoint subject to the rule is not allowed to
	// receive connections on.
	//
	// Example:
	// Any endpoint with the label "app=httpd" can not accept incoming
	// connections on port 80/tcp.
	//
	// +kubebuilder:validation:Optional
	ToPorts PortDenyRules `json:"toPorts,omitempty"`

	// ICMPs is a list of ICMP rule identified by type number
	// which the endpoint subject to the rule is not allowed to
	// receive connections on.
	//
	// Example:
	// Any endpoint with the label "app=httpd" can not accept incoming
	// type 8 ICMP connections.
	//
	// +kubebuilder:validation:Optional
	ICMPs ICMPRules `json:"icmps,omitempty"`
}
