github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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/metacubex/gvisor/pkg/log"
    22  	"github.com/metacubex/gvisor/pkg/tcpip"
    23  	"github.com/metacubex/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  }