github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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 "github.com/nicocha30/gvisor-ligolo/pkg/log" 22 "github.com/nicocha30/gvisor-ligolo/pkg/tcpip" 23 "github.com/nicocha30/gvisor-ligolo/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(PacketBufferPtr, 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(PacketBufferPtr, 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 PacketBufferPtr, 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 PacketBufferPtr, 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 PacketBufferPtr, 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 PacketBufferPtr, 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(PacketBufferPtr, 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(PacketBufferPtr, 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(PacketBufferPtr, 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 187 // Action implements Target.Action. 188 func (rt *DNATTarget) Action(pkt PacketBufferPtr, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { 189 // Sanity check. 190 if rt.NetworkProtocol != pkt.NetworkProtocolNumber { 191 panic(fmt.Sprintf( 192 "DNATTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d", 193 rt.NetworkProtocol, pkt.NetworkProtocolNumber)) 194 } 195 196 switch hook { 197 case Prerouting, Output: 198 case Input, Forward, Postrouting: 199 panic(fmt.Sprintf("%s not supported for DNAT", hook)) 200 default: 201 panic(fmt.Sprintf("%s unrecognized", hook)) 202 } 203 204 return dnatAction(pkt, hook, r, rt.Port, rt.Addr) 205 206 } 207 208 // RedirectTarget redirects the packet to this machine by modifying the 209 // destination port/IP. Outgoing packets are redirected to the loopback device, 210 // and incoming packets are redirected to the incoming interface (rather than 211 // forwarded). 212 type RedirectTarget struct { 213 // Port indicates port used to redirect. It is immutable. 214 Port uint16 215 216 // NetworkProtocol is the network protocol the target is used with. It 217 // is immutable. 218 NetworkProtocol tcpip.NetworkProtocolNumber 219 } 220 221 // Action implements Target.Action. 222 func (rt *RedirectTarget) Action(pkt PacketBufferPtr, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { 223 // Sanity check. 224 if rt.NetworkProtocol != pkt.NetworkProtocolNumber { 225 panic(fmt.Sprintf( 226 "RedirectTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d", 227 rt.NetworkProtocol, pkt.NetworkProtocolNumber)) 228 } 229 230 // Change the address to loopback (127.0.0.1 or ::1) in Output and to 231 // the primary address of the incoming interface in Prerouting. 232 var address tcpip.Address 233 switch hook { 234 case Output: 235 if pkt.NetworkProtocolNumber == header.IPv4ProtocolNumber { 236 address = tcpip.AddrFrom4([4]byte{127, 0, 0, 1}) 237 } else { 238 address = header.IPv6Loopback 239 } 240 case Prerouting: 241 // addressEP is expected to be set for the prerouting hook. 242 address = addressEP.MainAddress().Address 243 default: 244 panic("redirect target is supported only on output and prerouting hooks") 245 } 246 247 return dnatAction(pkt, hook, r, rt.Port, address) 248 } 249 250 // SNATTarget modifies the source port/IP in the outgoing packets. 251 type SNATTarget struct { 252 Addr tcpip.Address 253 Port uint16 254 255 // NetworkProtocol is the network protocol the target is used with. It 256 // is immutable. 257 NetworkProtocol tcpip.NetworkProtocolNumber 258 } 259 260 func dnatAction(pkt PacketBufferPtr, hook Hook, r *Route, port uint16, address tcpip.Address) (RuleVerdict, int) { 261 return natAction(pkt, hook, r, portOrIdentRange{start: port, size: 1}, address, true /* dnat */) 262 } 263 264 func targetPortRangeForTCPAndUDP(originalSrcPort uint16) portOrIdentRange { 265 // As per iptables(8), 266 // 267 // If no port range is specified, then source ports below 512 will be 268 // mapped to other ports below 512: those between 512 and 1023 inclusive 269 // will be mapped to ports below 1024, and other ports will be mapped to 270 // 1024 or above. 271 switch { 272 case originalSrcPort < 512: 273 return portOrIdentRange{start: 1, size: 511} 274 case originalSrcPort < 1024: 275 return portOrIdentRange{start: 1, size: 1023} 276 default: 277 return portOrIdentRange{start: 1024, size: math.MaxUint16 - 1023} 278 } 279 } 280 281 func snatAction(pkt PacketBufferPtr, hook Hook, r *Route, port uint16, address tcpip.Address) (RuleVerdict, int) { 282 portsOrIdents := portOrIdentRange{start: port, size: 1} 283 284 switch pkt.TransportProtocolNumber { 285 case header.UDPProtocolNumber: 286 if port == 0 { 287 portsOrIdents = targetPortRangeForTCPAndUDP(header.UDP(pkt.TransportHeader().Slice()).SourcePort()) 288 } 289 case header.TCPProtocolNumber: 290 if port == 0 { 291 portsOrIdents = targetPortRangeForTCPAndUDP(header.TCP(pkt.TransportHeader().Slice()).SourcePort()) 292 } 293 case header.ICMPv4ProtocolNumber, header.ICMPv6ProtocolNumber: 294 // Allow NAT-ing to any 16-bit value for ICMP's Ident field to match Linux 295 // behaviour. 296 // 297 // https://github.com/torvalds/linux/blob/58e1100fdc5990b0cc0d4beaf2562a92e621ac7d/net/netfilter/nf_nat_core.c#L391 298 portsOrIdents = portOrIdentRange{start: 0, size: math.MaxUint16 + 1} 299 } 300 301 return natAction(pkt, hook, r, portsOrIdents, address, false /* dnat */) 302 } 303 304 func natAction(pkt PacketBufferPtr, hook Hook, r *Route, portsOrIdents portOrIdentRange, address tcpip.Address, dnat bool) (RuleVerdict, int) { 305 // Drop the packet if network and transport header are not set. 306 if len(pkt.NetworkHeader().Slice()) == 0 || len(pkt.TransportHeader().Slice()) == 0 { 307 return RuleDrop, 0 308 } 309 310 if t := pkt.tuple; t != nil { 311 t.conn.performNAT(pkt, hook, r, portsOrIdents, address, dnat) 312 return RuleAccept, 0 313 } 314 315 return RuleDrop, 0 316 } 317 318 // Action implements Target.Action. 319 func (st *SNATTarget) Action(pkt PacketBufferPtr, hook Hook, r *Route, _ AddressableEndpoint) (RuleVerdict, int) { 320 // Sanity check. 321 if st.NetworkProtocol != pkt.NetworkProtocolNumber { 322 panic(fmt.Sprintf( 323 "SNATTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d", 324 st.NetworkProtocol, pkt.NetworkProtocolNumber)) 325 } 326 327 switch hook { 328 case Postrouting, Input: 329 case Prerouting, Output, Forward: 330 panic(fmt.Sprintf("%s not supported", hook)) 331 default: 332 panic(fmt.Sprintf("%s unrecognized", hook)) 333 } 334 335 return snatAction(pkt, hook, r, st.Port, st.Addr) 336 } 337 338 // MasqueradeTarget modifies the source port/IP in the outgoing packets. 339 type MasqueradeTarget struct { 340 // NetworkProtocol is the network protocol the target is used with. It 341 // is immutable. 342 NetworkProtocol tcpip.NetworkProtocolNumber 343 } 344 345 // Action implements Target.Action. 346 func (mt *MasqueradeTarget) Action(pkt PacketBufferPtr, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { 347 // Sanity check. 348 if mt.NetworkProtocol != pkt.NetworkProtocolNumber { 349 panic(fmt.Sprintf( 350 "MasqueradeTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d", 351 mt.NetworkProtocol, pkt.NetworkProtocolNumber)) 352 } 353 354 switch hook { 355 case Postrouting: 356 case Prerouting, Input, Forward, Output: 357 panic(fmt.Sprintf("masquerade target is supported only on postrouting hook; hook = %d", hook)) 358 default: 359 panic(fmt.Sprintf("%s unrecognized", hook)) 360 } 361 362 // addressEP is expected to be set for the postrouting hook. 363 ep := addressEP.AcquireOutgoingPrimaryAddress(pkt.Network().DestinationAddress(), false /* allowExpired */) 364 if ep == nil { 365 // No address exists that we can use as a source address. 366 return RuleDrop, 0 367 } 368 369 address := ep.AddressWithPrefix().Address 370 ep.DecRef() 371 return snatAction(pkt, hook, r, 0 /* port */, address) 372 } 373 374 func rewritePacket(n header.Network, t header.Transport, updateSRCFields, fullChecksum, updatePseudoHeader bool, newPortOrIdent uint16, newAddr tcpip.Address) { 375 switch t := t.(type) { 376 case header.ChecksummableTransport: 377 if updateSRCFields { 378 if fullChecksum { 379 t.SetSourcePortWithChecksumUpdate(newPortOrIdent) 380 } else { 381 t.SetSourcePort(newPortOrIdent) 382 } 383 } else { 384 if fullChecksum { 385 t.SetDestinationPortWithChecksumUpdate(newPortOrIdent) 386 } else { 387 t.SetDestinationPort(newPortOrIdent) 388 } 389 } 390 391 if updatePseudoHeader { 392 var oldAddr tcpip.Address 393 if updateSRCFields { 394 oldAddr = n.SourceAddress() 395 } else { 396 oldAddr = n.DestinationAddress() 397 } 398 399 t.UpdateChecksumPseudoHeaderAddress(oldAddr, newAddr, fullChecksum) 400 } 401 case header.ICMPv4: 402 switch icmpType := t.Type(); icmpType { 403 case header.ICMPv4Echo: 404 if updateSRCFields { 405 t.SetIdentWithChecksumUpdate(newPortOrIdent) 406 } 407 case header.ICMPv4EchoReply: 408 if !updateSRCFields { 409 t.SetIdentWithChecksumUpdate(newPortOrIdent) 410 } 411 default: 412 panic(fmt.Sprintf("unexpected ICMPv4 type = %d", icmpType)) 413 } 414 case header.ICMPv6: 415 switch icmpType := t.Type(); icmpType { 416 case header.ICMPv6EchoRequest: 417 if updateSRCFields { 418 t.SetIdentWithChecksumUpdate(newPortOrIdent) 419 } 420 case header.ICMPv6EchoReply: 421 if !updateSRCFields { 422 t.SetIdentWithChecksumUpdate(newPortOrIdent) 423 } 424 default: 425 panic(fmt.Sprintf("unexpected ICMPv4 type = %d", icmpType)) 426 } 427 428 var oldAddr tcpip.Address 429 if updateSRCFields { 430 oldAddr = n.SourceAddress() 431 } else { 432 oldAddr = n.DestinationAddress() 433 } 434 435 t.UpdateChecksumPseudoHeaderAddress(oldAddr, newAddr) 436 default: 437 panic(fmt.Sprintf("unhandled transport = %#v", t)) 438 } 439 440 if checksummableNetHeader, ok := n.(header.ChecksummableNetwork); ok { 441 if updateSRCFields { 442 checksummableNetHeader.SetSourceAddressWithChecksumUpdate(newAddr) 443 } else { 444 checksummableNetHeader.SetDestinationAddressWithChecksumUpdate(newAddr) 445 } 446 } else if updateSRCFields { 447 n.SetSourceAddress(newAddr) 448 } else { 449 n.SetDestinationAddress(newAddr) 450 } 451 }