gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/stack/iptables_targets.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package stack 16 17 import ( 18 "fmt" 19 "math" 20 21 "gvisor.dev/gvisor/pkg/log" 22 "gvisor.dev/gvisor/pkg/tcpip" 23 "gvisor.dev/gvisor/pkg/tcpip/header" 24 ) 25 26 // AcceptTarget accepts packets. 27 type AcceptTarget struct { 28 // NetworkProtocol is the network protocol the target is used with. 29 NetworkProtocol tcpip.NetworkProtocolNumber 30 } 31 32 // Action implements Target.Action. 33 func (*AcceptTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { 34 return RuleAccept, 0 35 } 36 37 // DropTarget drops packets. 38 type DropTarget struct { 39 // NetworkProtocol is the network protocol the target is used with. 40 NetworkProtocol tcpip.NetworkProtocolNumber 41 } 42 43 // Action implements Target.Action. 44 func (*DropTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { 45 return RuleDrop, 0 46 } 47 48 // RejectIPv4WithHandler handles rejecting a packet. 49 type RejectIPv4WithHandler interface { 50 // SendRejectionError sends an error packet in response to the packet. 51 SendRejectionError(pkt *PacketBuffer, rejectWith RejectIPv4WithICMPType, inputHook bool) tcpip.Error 52 } 53 54 // RejectIPv4WithICMPType indicates the type of ICMP error that should be sent. 55 type RejectIPv4WithICMPType int 56 57 // The types of errors that may be returned when rejecting IPv4 packets. 58 const ( 59 _ RejectIPv4WithICMPType = iota 60 RejectIPv4WithICMPNetUnreachable 61 RejectIPv4WithICMPHostUnreachable 62 RejectIPv4WithICMPPortUnreachable 63 RejectIPv4WithICMPNetProhibited 64 RejectIPv4WithICMPHostProhibited 65 RejectIPv4WithICMPAdminProhibited 66 ) 67 68 // RejectIPv4Target drops packets and sends back an error packet in response to the 69 // matched packet. 70 type RejectIPv4Target struct { 71 Handler RejectIPv4WithHandler 72 RejectWith RejectIPv4WithICMPType 73 } 74 75 // Action implements Target.Action. 76 func (rt *RejectIPv4Target) Action(pkt *PacketBuffer, hook Hook, _ *Route, _ AddressableEndpoint) (RuleVerdict, int) { 77 switch hook { 78 case Input, Forward, Output: 79 // There is nothing reasonable for us to do in response to an error here; 80 // we already drop the packet. 81 _ = rt.Handler.SendRejectionError(pkt, rt.RejectWith, hook == Input) 82 return RuleDrop, 0 83 case Prerouting, Postrouting: 84 panic(fmt.Sprintf("%s hook not supported for REDIRECT", hook)) 85 default: 86 panic(fmt.Sprintf("unhandled hook = %s", hook)) 87 } 88 } 89 90 // RejectIPv6WithHandler handles rejecting a packet. 91 type RejectIPv6WithHandler interface { 92 // SendRejectionError sends an error packet in response to the packet. 93 SendRejectionError(pkt *PacketBuffer, rejectWith RejectIPv6WithICMPType, forwardingHook bool) tcpip.Error 94 } 95 96 // RejectIPv6WithICMPType indicates the type of ICMP error that should be sent. 97 type RejectIPv6WithICMPType int 98 99 // The types of errors that may be returned when rejecting IPv6 packets. 100 const ( 101 _ RejectIPv6WithICMPType = iota 102 RejectIPv6WithICMPNoRoute 103 RejectIPv6WithICMPAddrUnreachable 104 RejectIPv6WithICMPPortUnreachable 105 RejectIPv6WithICMPAdminProhibited 106 ) 107 108 // RejectIPv6Target drops packets and sends back an error packet in response to the 109 // matched packet. 110 type RejectIPv6Target struct { 111 Handler RejectIPv6WithHandler 112 RejectWith RejectIPv6WithICMPType 113 } 114 115 // Action implements Target.Action. 116 func (rt *RejectIPv6Target) Action(pkt *PacketBuffer, hook Hook, _ *Route, _ AddressableEndpoint) (RuleVerdict, int) { 117 switch hook { 118 case Input, Forward, Output: 119 // There is nothing reasonable for us to do in response to an error here; 120 // we already drop the packet. 121 _ = rt.Handler.SendRejectionError(pkt, rt.RejectWith, hook == Input) 122 return RuleDrop, 0 123 case Prerouting, Postrouting: 124 panic(fmt.Sprintf("%s hook not supported for REDIRECT", hook)) 125 default: 126 panic(fmt.Sprintf("unhandled hook = %s", hook)) 127 } 128 } 129 130 // ErrorTarget logs an error and drops the packet. It represents a target that 131 // should be unreachable. 132 type ErrorTarget struct { 133 // NetworkProtocol is the network protocol the target is used with. 134 NetworkProtocol tcpip.NetworkProtocolNumber 135 } 136 137 // Action implements Target.Action. 138 func (*ErrorTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { 139 log.Debugf("ErrorTarget triggered.") 140 return RuleDrop, 0 141 } 142 143 // UserChainTarget marks a rule as the beginning of a user chain. 144 type UserChainTarget struct { 145 // Name is the chain name. 146 Name string 147 148 // NetworkProtocol is the network protocol the target is used with. 149 NetworkProtocol tcpip.NetworkProtocolNumber 150 } 151 152 // Action implements Target.Action. 153 func (*UserChainTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { 154 panic("UserChainTarget should never be called.") 155 } 156 157 // ReturnTarget returns from the current chain. If the chain is a built-in, the 158 // hook's underflow should be called. 159 type ReturnTarget struct { 160 // NetworkProtocol is the network protocol the target is used with. 161 NetworkProtocol tcpip.NetworkProtocolNumber 162 } 163 164 // Action implements Target.Action. 165 func (*ReturnTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { 166 return RuleReturn, 0 167 } 168 169 // DNATTarget modifies the destination port/IP of packets. 170 type DNATTarget struct { 171 // The new destination address for packets. 172 // 173 // Immutable. 174 Addr tcpip.Address 175 176 // The new destination port for packets. 177 // 178 // Immutable. 179 Port uint16 180 181 // NetworkProtocol is the network protocol the target is used with. 182 // 183 // Immutable. 184 NetworkProtocol tcpip.NetworkProtocolNumber 185 186 // ChangeAddress indicates whether we should check addresses. 187 // 188 // Immutable. 189 ChangeAddress bool 190 191 // ChangePort indicates whether we should check ports. 192 // 193 // Immutable. 194 ChangePort bool 195 } 196 197 // Action implements Target.Action. 198 func (rt *DNATTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { 199 // Sanity check. 200 if rt.NetworkProtocol != pkt.NetworkProtocolNumber { 201 panic(fmt.Sprintf( 202 "DNATTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d", 203 rt.NetworkProtocol, pkt.NetworkProtocolNumber)) 204 } 205 206 switch hook { 207 case Prerouting, Output: 208 case Input, Forward, Postrouting: 209 panic(fmt.Sprintf("%s not supported for DNAT", hook)) 210 default: 211 panic(fmt.Sprintf("%s unrecognized", hook)) 212 } 213 214 return dnatAction(pkt, hook, r, rt.Port, rt.Addr, rt.ChangePort, rt.ChangeAddress) 215 216 } 217 218 // RedirectTarget redirects the packet to this machine by modifying the 219 // destination port/IP. Outgoing packets are redirected to the loopback device, 220 // and incoming packets are redirected to the incoming interface (rather than 221 // forwarded). 222 type RedirectTarget struct { 223 // Port indicates port used to redirect. It is immutable. 224 Port uint16 225 226 // NetworkProtocol is the network protocol the target is used with. It 227 // is immutable. 228 NetworkProtocol tcpip.NetworkProtocolNumber 229 } 230 231 // Action implements Target.Action. 232 func (rt *RedirectTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { 233 // Sanity check. 234 if rt.NetworkProtocol != pkt.NetworkProtocolNumber { 235 panic(fmt.Sprintf( 236 "RedirectTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d", 237 rt.NetworkProtocol, pkt.NetworkProtocolNumber)) 238 } 239 240 // Change the address to loopback (127.0.0.1 or ::1) in Output and to 241 // the primary address of the incoming interface in Prerouting. 242 var address tcpip.Address 243 switch hook { 244 case Output: 245 if pkt.NetworkProtocolNumber == header.IPv4ProtocolNumber { 246 address = tcpip.AddrFrom4([4]byte{127, 0, 0, 1}) 247 } else { 248 address = header.IPv6Loopback 249 } 250 case Prerouting: 251 // addressEP is expected to be set for the prerouting hook. 252 address = addressEP.MainAddress().Address 253 default: 254 panic("redirect target is supported only on output and prerouting hooks") 255 } 256 257 return dnatAction(pkt, hook, r, rt.Port, address, true /* changePort */, true /* changeAddress */) 258 } 259 260 // SNATTarget modifies the source port/IP in the outgoing packets. 261 type SNATTarget struct { 262 Addr tcpip.Address 263 Port uint16 264 265 // NetworkProtocol is the network protocol the target is used with. It 266 // is immutable. 267 NetworkProtocol tcpip.NetworkProtocolNumber 268 269 // ChangeAddress indicates whether we should check addresses. 270 // 271 // Immutable. 272 ChangeAddress bool 273 274 // ChangePort indicates whether we should check ports. 275 // 276 // Immutable. 277 ChangePort bool 278 } 279 280 func dnatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcpip.Address, changePort, changeAddress bool) (RuleVerdict, int) { 281 return natAction(pkt, hook, r, portOrIdentRange{start: port, size: 1}, address, true /* dnat */, changePort, changeAddress) 282 } 283 284 func targetPortRangeForTCPAndUDP(originalSrcPort uint16) portOrIdentRange { 285 // As per iptables(8), 286 // 287 // If no port range is specified, then source ports below 512 will be 288 // mapped to other ports below 512: those between 512 and 1023 inclusive 289 // will be mapped to ports below 1024, and other ports will be mapped to 290 // 1024 or above. 291 switch { 292 case originalSrcPort < 512: 293 return portOrIdentRange{start: 1, size: 511} 294 case originalSrcPort < 1024: 295 return portOrIdentRange{start: 1, size: 1023} 296 default: 297 return portOrIdentRange{start: 1024, size: math.MaxUint16 - 1023} 298 } 299 } 300 301 func snatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcpip.Address, changePort, changeAddress bool) (RuleVerdict, int) { 302 portsOrIdents := portOrIdentRange{start: port, size: 1} 303 304 switch pkt.TransportProtocolNumber { 305 case header.UDPProtocolNumber: 306 if port == 0 { 307 portsOrIdents = targetPortRangeForTCPAndUDP(header.UDP(pkt.TransportHeader().Slice()).SourcePort()) 308 } 309 case header.TCPProtocolNumber: 310 if port == 0 { 311 portsOrIdents = targetPortRangeForTCPAndUDP(header.TCP(pkt.TransportHeader().Slice()).SourcePort()) 312 } 313 case header.ICMPv4ProtocolNumber, header.ICMPv6ProtocolNumber: 314 // Allow NAT-ing to any 16-bit value for ICMP's Ident field to match Linux 315 // behaviour. 316 // 317 // https://github.com/torvalds/linux/blob/58e1100fdc5990b0cc0d4beaf2562a92e621ac7d/net/netfilter/nf_nat_core.c#L391 318 portsOrIdents = portOrIdentRange{start: 0, size: math.MaxUint16 + 1} 319 } 320 321 return natAction(pkt, hook, r, portsOrIdents, address, false /* dnat */, changePort, changeAddress) 322 } 323 324 func natAction(pkt *PacketBuffer, hook Hook, r *Route, portsOrIdents portOrIdentRange, address tcpip.Address, dnat, changePort, changeAddress bool) (RuleVerdict, int) { 325 // Drop the packet if network and transport header are not set. 326 if len(pkt.NetworkHeader().Slice()) == 0 || len(pkt.TransportHeader().Slice()) == 0 { 327 return RuleDrop, 0 328 } 329 330 if t := pkt.tuple; t != nil { 331 t.conn.performNAT(pkt, hook, r, portsOrIdents, address, dnat, changePort, changeAddress) 332 return RuleAccept, 0 333 } 334 335 return RuleDrop, 0 336 } 337 338 // Action implements Target.Action. 339 func (st *SNATTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, _ AddressableEndpoint) (RuleVerdict, int) { 340 // Sanity check. 341 if st.NetworkProtocol != pkt.NetworkProtocolNumber { 342 panic(fmt.Sprintf( 343 "SNATTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d", 344 st.NetworkProtocol, pkt.NetworkProtocolNumber)) 345 } 346 347 switch hook { 348 case Postrouting, Input: 349 case Prerouting, Output, Forward: 350 panic(fmt.Sprintf("%s not supported", hook)) 351 default: 352 panic(fmt.Sprintf("%s unrecognized", hook)) 353 } 354 355 return snatAction(pkt, hook, r, st.Port, st.Addr, st.ChangePort, st.ChangeAddress) 356 } 357 358 // MasqueradeTarget modifies the source port/IP in the outgoing packets. 359 type MasqueradeTarget struct { 360 // NetworkProtocol is the network protocol the target is used with. It 361 // is immutable. 362 NetworkProtocol tcpip.NetworkProtocolNumber 363 } 364 365 // Action implements Target.Action. 366 func (mt *MasqueradeTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { 367 // Sanity check. 368 if mt.NetworkProtocol != pkt.NetworkProtocolNumber { 369 panic(fmt.Sprintf( 370 "MasqueradeTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d", 371 mt.NetworkProtocol, pkt.NetworkProtocolNumber)) 372 } 373 374 switch hook { 375 case Postrouting: 376 case Prerouting, Input, Forward, Output: 377 panic(fmt.Sprintf("masquerade target is supported only on postrouting hook; hook = %d", hook)) 378 default: 379 panic(fmt.Sprintf("%s unrecognized", hook)) 380 } 381 382 // addressEP is expected to be set for the postrouting hook. 383 ep := addressEP.AcquireOutgoingPrimaryAddress(pkt.Network().DestinationAddress(), tcpip.Address{} /* srcHint */, false /* allowExpired */) 384 if ep == nil { 385 // No address exists that we can use as a source address. 386 return RuleDrop, 0 387 } 388 389 address := ep.AddressWithPrefix().Address 390 ep.DecRef() 391 return snatAction(pkt, hook, r, 0 /* port */, address, true /* changePort */, true /* changeAddress */) 392 } 393 394 func rewritePacket(n header.Network, t header.Transport, updateSRCFields, fullChecksum, updatePseudoHeader bool, newPortOrIdent uint16, newAddr tcpip.Address) { 395 switch t := t.(type) { 396 case header.ChecksummableTransport: 397 if updateSRCFields { 398 if fullChecksum { 399 t.SetSourcePortWithChecksumUpdate(newPortOrIdent) 400 } else { 401 t.SetSourcePort(newPortOrIdent) 402 } 403 } else { 404 if fullChecksum { 405 t.SetDestinationPortWithChecksumUpdate(newPortOrIdent) 406 } else { 407 t.SetDestinationPort(newPortOrIdent) 408 } 409 } 410 411 if updatePseudoHeader { 412 var oldAddr tcpip.Address 413 if updateSRCFields { 414 oldAddr = n.SourceAddress() 415 } else { 416 oldAddr = n.DestinationAddress() 417 } 418 419 t.UpdateChecksumPseudoHeaderAddress(oldAddr, newAddr, fullChecksum) 420 } 421 case header.ICMPv4: 422 switch icmpType := t.Type(); icmpType { 423 case header.ICMPv4Echo: 424 if updateSRCFields { 425 t.SetIdentWithChecksumUpdate(newPortOrIdent) 426 } 427 case header.ICMPv4EchoReply: 428 if !updateSRCFields { 429 t.SetIdentWithChecksumUpdate(newPortOrIdent) 430 } 431 default: 432 panic(fmt.Sprintf("unexpected ICMPv4 type = %d", icmpType)) 433 } 434 case header.ICMPv6: 435 switch icmpType := t.Type(); icmpType { 436 case header.ICMPv6EchoRequest: 437 if updateSRCFields { 438 t.SetIdentWithChecksumUpdate(newPortOrIdent) 439 } 440 case header.ICMPv6EchoReply: 441 if !updateSRCFields { 442 t.SetIdentWithChecksumUpdate(newPortOrIdent) 443 } 444 default: 445 panic(fmt.Sprintf("unexpected ICMPv4 type = %d", icmpType)) 446 } 447 448 var oldAddr tcpip.Address 449 if updateSRCFields { 450 oldAddr = n.SourceAddress() 451 } else { 452 oldAddr = n.DestinationAddress() 453 } 454 455 t.UpdateChecksumPseudoHeaderAddress(oldAddr, newAddr) 456 default: 457 panic(fmt.Sprintf("unhandled transport = %#v", t)) 458 } 459 460 if checksummableNetHeader, ok := n.(header.ChecksummableNetwork); ok { 461 if updateSRCFields { 462 checksummableNetHeader.SetSourceAddressWithChecksumUpdate(newAddr) 463 } else { 464 checksummableNetHeader.SetDestinationAddressWithChecksumUpdate(newAddr) 465 } 466 } else if updateSRCFields { 467 n.SetSourceAddress(newAddr) 468 } else { 469 n.SetDestinationAddress(newAddr) 470 } 471 }