github.com/cilium/cilium@v1.16.2/pkg/policy/api/icmp.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package api 5 6 import ( 7 "encoding/json" 8 "fmt" 9 10 "k8s.io/apimachinery/pkg/util/intstr" 11 ) 12 13 const ( 14 IPv4Family = "IPv4" 15 IPv6Family = "IPv6" 16 ) 17 18 var icmpIpv4TypeNameToCode = map[string]string{ 19 "EchoReply": "0", 20 "DestinationUnreachable": "3", 21 "Redirect": "5", 22 "Echo": "8", 23 "EchoRequest": "8", 24 "RouterAdvertisement": "9", 25 "RouterSelection": "10", 26 "TimeExceeded": "11", 27 "ParameterProblem": "12", 28 "Timestamp": "13", 29 "TimestampReply": "14", 30 "Photuris": "40", 31 "ExtendedEchoRequest": "42", 32 "ExtendedEchoReply": "43", 33 } 34 35 var icmpIpv6TypeNameToCode = map[string]string{ 36 "DestinationUnreachable": "1", 37 "PacketTooBig": "2", 38 "TimeExceeded": "3", 39 "ParameterProblem": "4", 40 "EchoRequest": "128", 41 "EchoReply": "129", 42 "MulticastListenerQuery": "130", 43 "MulticastListenerReport": "131", 44 "MulticastListenerDone": "132", 45 "RouterSolicitation": "133", 46 "RouterAdvertisement": "134", 47 "NeighborSolicitation": "135", 48 "NeighborAdvertisement": "136", 49 "RedirectMessage": "137", 50 "RouterRenumbering": "138", 51 "ICMPNodeInformationQuery": "139", 52 "ICMPNodeInformationResponse": "140", 53 "InverseNeighborDiscoverySolicitation": "141", 54 "InverseNeighborDiscoveryAdvertisement": "142", 55 "HomeAgentAddressDiscoveryRequest": "144", 56 "HomeAgentAddressDiscoveryReply": "145", 57 "MobilePrefixSolicitation": "146", 58 "MobilePrefixAdvertisement": "147", 59 "DuplicateAddressRequestCodeSuffix": "157", 60 "DuplicateAddressConfirmationCodeSuffix": "158", 61 "ExtendedEchoRequest": "160", 62 "ExtendedEchoReply": "161", 63 } 64 65 type ICMPRules []ICMPRule 66 67 // ICMPRule is a list of ICMP fields. 68 type ICMPRule struct { 69 // Fields is a list of ICMP fields. 70 // 71 // +kubebuilder:validation:Optional 72 // +kubebuilder:validation:MaxItems=40 73 Fields []ICMPField `json:"fields,omitempty"` 74 } 75 76 // ICMPField is a ICMP field. 77 // 78 // +deepequal-gen=true 79 // +deepequal-gen:private-method=true 80 type ICMPField struct { 81 // Family is a IP address version. 82 // Currently, we support `IPv4` and `IPv6`. 83 // `IPv4` is set as default. 84 // 85 // +kubebuilder:default=IPv4 86 // +kubebuilder:validation:Optional 87 // +kubebuilder:validation:Enum=IPv4;IPv6 88 Family string `json:"family,omitempty"` 89 90 // Type is a ICMP-type. 91 // It should be an 8bit code (0-255), or it's CamelCase name (for example, "EchoReply"). 92 // Allowed ICMP types are: 93 // Ipv4: EchoReply | DestinationUnreachable | Redirect | Echo | EchoRequest | 94 // RouterAdvertisement | RouterSelection | TimeExceeded | ParameterProblem | 95 // Timestamp | TimestampReply | Photuris | ExtendedEcho Request | ExtendedEcho Reply 96 // Ipv6: DestinationUnreachable | PacketTooBig | TimeExceeded | ParameterProblem | 97 // EchoRequest | EchoReply | MulticastListenerQuery| MulticastListenerReport | 98 // MulticastListenerDone | RouterSolicitation | RouterAdvertisement | NeighborSolicitation | 99 // NeighborAdvertisement | RedirectMessage | RouterRenumbering | ICMPNodeInformationQuery | 100 // ICMPNodeInformationResponse | InverseNeighborDiscoverySolicitation | InverseNeighborDiscoveryAdvertisement | 101 // HomeAgentAddressDiscoveryRequest | HomeAgentAddressDiscoveryReply | MobilePrefixSolicitation | 102 // MobilePrefixAdvertisement | DuplicateAddressRequestCodeSuffix | DuplicateAddressConfirmationCodeSuffix | 103 // ExtendedEchoRequest | ExtendedEchoReply 104 // 105 // +deepequal-gen=false 106 // +kubebuilder:validation:XIntOrString 107 // +kubebuilder:validation:Pattern="^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]|EchoReply|DestinationUnreachable|Redirect|Echo|RouterAdvertisement|RouterSelection|TimeExceeded|ParameterProblem|Timestamp|TimestampReply|Photuris|ExtendedEchoRequest|ExtendedEcho Reply|PacketTooBig|ParameterProblem|EchoRequest|MulticastListenerQuery|MulticastListenerReport|MulticastListenerDone|RouterSolicitation|RouterAdvertisement|NeighborSolicitation|NeighborAdvertisement|RedirectMessage|RouterRenumbering|ICMPNodeInformationQuery|ICMPNodeInformationResponse|InverseNeighborDiscoverySolicitation|InverseNeighborDiscoveryAdvertisement|HomeAgentAddressDiscoveryRequest|HomeAgentAddressDiscoveryReply|MobilePrefixSolicitation|MobilePrefixAdvertisement|DuplicateAddressRequestCodeSuffix|DuplicateAddressConfirmationCodeSuffix)$" 108 Type *intstr.IntOrString `json:"type"` 109 } 110 111 func (i *ICMPField) DeepEqual(o *ICMPField) bool { 112 if i == nil { 113 return o == nil 114 } 115 116 if i.Type.String() != o.Type.String() { 117 return false 118 } 119 120 return i.deepEqual(o) 121 } 122 123 // UnmarshalJSON unmarshals the ICMPField from the byte array and check if the Type matches with IP version. 124 func (i *ICMPField) UnmarshalJSON(value []byte) error { 125 var t struct { 126 Family string `json:"family,omitempty"` 127 Type *intstr.IntOrString `json:"type"` 128 } 129 130 if err := json.Unmarshal(value, &t); err != nil { 131 return err 132 } 133 134 // If i.Type is ICMP type name, the value should be checked if it belongs to the map for the given family. 135 if t.Type.String() != "0" && t.Type.IntValue() == 0 { 136 name := t.Type.String() 137 var nameToCode map[string]string 138 switch t.Family { 139 case IPv6Family: 140 nameToCode = icmpIpv6TypeNameToCode 141 default: 142 nameToCode = icmpIpv4TypeNameToCode 143 } 144 145 if _, ok := nameToCode[name]; !ok { 146 return fmt.Errorf("ICMP type %s not found in %s", name, t.Family) 147 } 148 } 149 150 i.Family = t.Family 151 i.Type = t.Type 152 153 return nil 154 } 155 156 // Iterate iterates over all elements of ICMPRules. 157 func (ir ICMPRules) Iterate(f func(pr Ports) error) error { 158 for i := range ir { 159 if err := f(&ir[i]); err != nil { 160 return err 161 } 162 } 163 return nil 164 } 165 166 // Len returns the length of the elements of ICMPRules. 167 func (ir ICMPRules) Len() int { 168 return len(ir) 169 } 170 171 // GetPortProtocols generates PortProtocol slice from ICMPRule and returns it. 172 func (ir ICMPRule) GetPortProtocols() []PortProtocol { 173 var pps []PortProtocol 174 for _, t := range ir.Fields { 175 pp := t.PortProtocol() 176 pps = append(pps, *pp) 177 } 178 return pps 179 } 180 181 // GetPortRule generates PortRule from ICMPRule and returns it. 182 func (ir ICMPRule) GetPortRule() *PortRule { 183 var pps []PortProtocol 184 for _, t := range ir.Fields { 185 pp := t.PortProtocol() 186 pps = append(pps, *pp) 187 } 188 pr := PortRule{ 189 Ports: pps, 190 } 191 return &pr 192 } 193 194 // PortProtocol translates ICMPType to PortProtocol. 195 func (i ICMPField) PortProtocol() *PortProtocol { 196 var proto L4Proto 197 var nameToCode map[string]string 198 199 switch i.Family { 200 case IPv6Family: 201 proto = ProtoICMPv6 202 nameToCode = icmpIpv6TypeNameToCode 203 204 default: 205 proto = ProtoICMP 206 nameToCode = icmpIpv4TypeNameToCode 207 } 208 209 port := i.Type.String() 210 if name, ok := nameToCode[port]; ok { 211 port = name 212 } 213 214 pr := PortProtocol{ 215 Port: port, 216 Protocol: proto, 217 } 218 return &pr 219 }