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  }