inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/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  	"inet.af/netstack/log"
    22  	"inet.af/netstack/tcpip"
    23  	"inet.af/netstack/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  // ErrorTarget logs an error and drops the packet. It represents a target that
    49  // should be unreachable.
    50  type ErrorTarget struct {
    51  	// NetworkProtocol is the network protocol the target is used with.
    52  	NetworkProtocol tcpip.NetworkProtocolNumber
    53  }
    54  
    55  // Action implements Target.Action.
    56  func (*ErrorTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
    57  	log.Debugf("ErrorTarget triggered.")
    58  	return RuleDrop, 0
    59  }
    60  
    61  // UserChainTarget marks a rule as the beginning of a user chain.
    62  type UserChainTarget struct {
    63  	// Name is the chain name.
    64  	Name string
    65  
    66  	// NetworkProtocol is the network protocol the target is used with.
    67  	NetworkProtocol tcpip.NetworkProtocolNumber
    68  }
    69  
    70  // Action implements Target.Action.
    71  func (*UserChainTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
    72  	panic("UserChainTarget should never be called.")
    73  }
    74  
    75  // ReturnTarget returns from the current chain. If the chain is a built-in, the
    76  // hook's underflow should be called.
    77  type ReturnTarget struct {
    78  	// NetworkProtocol is the network protocol the target is used with.
    79  	NetworkProtocol tcpip.NetworkProtocolNumber
    80  }
    81  
    82  // Action implements Target.Action.
    83  func (*ReturnTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
    84  	return RuleReturn, 0
    85  }
    86  
    87  // DNATTarget modifies the destination port/IP of packets.
    88  type DNATTarget struct {
    89  	// The new destination address for packets.
    90  	//
    91  	// Immutable.
    92  	Addr tcpip.Address
    93  
    94  	// The new destination port for packets.
    95  	//
    96  	// Immutable.
    97  	Port uint16
    98  
    99  	// NetworkProtocol is the network protocol the target is used with.
   100  	//
   101  	// Immutable.
   102  	NetworkProtocol tcpip.NetworkProtocolNumber
   103  }
   104  
   105  // Action implements Target.Action.
   106  func (rt *DNATTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) {
   107  	// Sanity check.
   108  	if rt.NetworkProtocol != pkt.NetworkProtocolNumber {
   109  		panic(fmt.Sprintf(
   110  			"DNATTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
   111  			rt.NetworkProtocol, pkt.NetworkProtocolNumber))
   112  	}
   113  
   114  	switch hook {
   115  	case Prerouting, Output:
   116  	case Input, Forward, Postrouting:
   117  		panic(fmt.Sprintf("%s not supported for DNAT", hook))
   118  	default:
   119  		panic(fmt.Sprintf("%s unrecognized", hook))
   120  	}
   121  
   122  	return dnatAction(pkt, hook, r, rt.Port, rt.Addr)
   123  
   124  }
   125  
   126  // RedirectTarget redirects the packet to this machine by modifying the
   127  // destination port/IP. Outgoing packets are redirected to the loopback device,
   128  // and incoming packets are redirected to the incoming interface (rather than
   129  // forwarded).
   130  type RedirectTarget struct {
   131  	// Port indicates port used to redirect. It is immutable.
   132  	Port uint16
   133  
   134  	// NetworkProtocol is the network protocol the target is used with. It
   135  	// is immutable.
   136  	NetworkProtocol tcpip.NetworkProtocolNumber
   137  }
   138  
   139  // Action implements Target.Action.
   140  func (rt *RedirectTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) {
   141  	// Sanity check.
   142  	if rt.NetworkProtocol != pkt.NetworkProtocolNumber {
   143  		panic(fmt.Sprintf(
   144  			"RedirectTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
   145  			rt.NetworkProtocol, pkt.NetworkProtocolNumber))
   146  	}
   147  
   148  	// Change the address to loopback (127.0.0.1 or ::1) in Output and to
   149  	// the primary address of the incoming interface in Prerouting.
   150  	var address tcpip.Address
   151  	switch hook {
   152  	case Output:
   153  		if pkt.NetworkProtocolNumber == header.IPv4ProtocolNumber {
   154  			address = tcpip.Address([]byte{127, 0, 0, 1})
   155  		} else {
   156  			address = header.IPv6Loopback
   157  		}
   158  	case Prerouting:
   159  		// addressEP is expected to be set for the prerouting hook.
   160  		address = addressEP.MainAddress().Address
   161  	default:
   162  		panic("redirect target is supported only on output and prerouting hooks")
   163  	}
   164  
   165  	return dnatAction(pkt, hook, r, rt.Port, address)
   166  }
   167  
   168  // SNATTarget modifies the source port/IP in the outgoing packets.
   169  type SNATTarget struct {
   170  	Addr tcpip.Address
   171  	Port uint16
   172  
   173  	// NetworkProtocol is the network protocol the target is used with. It
   174  	// is immutable.
   175  	NetworkProtocol tcpip.NetworkProtocolNumber
   176  }
   177  
   178  func dnatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcpip.Address) (RuleVerdict, int) {
   179  	return natAction(pkt, hook, r, portRange{start: port, size: 1}, address, true /* dnat */)
   180  }
   181  
   182  func snatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcpip.Address) (RuleVerdict, int) {
   183  	ports := portRange{start: port, size: 1}
   184  	if port == 0 {
   185  		// As per iptables(8),
   186  		//
   187  		//   If no port range is specified, then source ports below 512 will be
   188  		//   mapped to other ports below 512: those between 512 and 1023 inclusive
   189  		//   will be mapped to ports below 1024, and other ports will be mapped to
   190  		//   1024 or above.
   191  		switch protocol := pkt.TransportProtocolNumber; protocol {
   192  		case header.UDPProtocolNumber:
   193  			port = header.UDP(pkt.TransportHeader().View()).SourcePort()
   194  		case header.TCPProtocolNumber:
   195  			port = header.TCP(pkt.TransportHeader().View()).SourcePort()
   196  		default:
   197  			panic(fmt.Sprintf("unsupported transport protocol = %d", pkt.TransportProtocolNumber))
   198  		}
   199  
   200  		switch {
   201  		case port < 512:
   202  			ports = portRange{start: 1, size: 511}
   203  		case port < 1024:
   204  			ports = portRange{start: 1, size: 1023}
   205  		default:
   206  			ports = portRange{start: 1024, size: math.MaxUint16 - 1023}
   207  		}
   208  	}
   209  
   210  	return natAction(pkt, hook, r, ports, address, false /* dnat */)
   211  }
   212  
   213  func natAction(pkt *PacketBuffer, hook Hook, r *Route, ports portRange, address tcpip.Address, dnat bool) (RuleVerdict, int) {
   214  	// Drop the packet if network and transport header are not set.
   215  	if pkt.NetworkHeader().View().IsEmpty() || pkt.TransportHeader().View().IsEmpty() {
   216  		return RuleDrop, 0
   217  	}
   218  
   219  	if t := pkt.tuple; t != nil {
   220  		t.conn.performNAT(pkt, hook, r, ports, address, dnat)
   221  		return RuleAccept, 0
   222  	}
   223  
   224  	return RuleDrop, 0
   225  }
   226  
   227  // Action implements Target.Action.
   228  func (st *SNATTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, _ AddressableEndpoint) (RuleVerdict, int) {
   229  	// Sanity check.
   230  	if st.NetworkProtocol != pkt.NetworkProtocolNumber {
   231  		panic(fmt.Sprintf(
   232  			"SNATTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
   233  			st.NetworkProtocol, pkt.NetworkProtocolNumber))
   234  	}
   235  
   236  	switch hook {
   237  	case Postrouting, Input:
   238  	case Prerouting, Output, Forward:
   239  		panic(fmt.Sprintf("%s not supported", hook))
   240  	default:
   241  		panic(fmt.Sprintf("%s unrecognized", hook))
   242  	}
   243  
   244  	return snatAction(pkt, hook, r, st.Port, st.Addr)
   245  }
   246  
   247  // MasqueradeTarget modifies the source port/IP in the outgoing packets.
   248  type MasqueradeTarget struct {
   249  	// NetworkProtocol is the network protocol the target is used with. It
   250  	// is immutable.
   251  	NetworkProtocol tcpip.NetworkProtocolNumber
   252  }
   253  
   254  // Action implements Target.Action.
   255  func (mt *MasqueradeTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) {
   256  	// Sanity check.
   257  	if mt.NetworkProtocol != pkt.NetworkProtocolNumber {
   258  		panic(fmt.Sprintf(
   259  			"MasqueradeTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
   260  			mt.NetworkProtocol, pkt.NetworkProtocolNumber))
   261  	}
   262  
   263  	switch hook {
   264  	case Postrouting:
   265  	case Prerouting, Input, Forward, Output:
   266  		panic(fmt.Sprintf("masquerade target is supported only on postrouting hook; hook = %d", hook))
   267  	default:
   268  		panic(fmt.Sprintf("%s unrecognized", hook))
   269  	}
   270  
   271  	// addressEP is expected to be set for the postrouting hook.
   272  	ep := addressEP.AcquireOutgoingPrimaryAddress(pkt.Network().DestinationAddress(), false /* allowExpired */)
   273  	if ep == nil {
   274  		// No address exists that we can use as a source address.
   275  		return RuleDrop, 0
   276  	}
   277  
   278  	address := ep.AddressWithPrefix().Address
   279  	ep.DecRef()
   280  	return snatAction(pkt, hook, r, 0 /* port */, address)
   281  }
   282  
   283  func rewritePacket(n header.Network, t header.ChecksummableTransport, updateSRCFields, fullChecksum, updatePseudoHeader bool, newPort uint16, newAddr tcpip.Address) {
   284  	if updateSRCFields {
   285  		if fullChecksum {
   286  			t.SetSourcePortWithChecksumUpdate(newPort)
   287  		} else {
   288  			t.SetSourcePort(newPort)
   289  		}
   290  	} else {
   291  		if fullChecksum {
   292  			t.SetDestinationPortWithChecksumUpdate(newPort)
   293  		} else {
   294  			t.SetDestinationPort(newPort)
   295  		}
   296  	}
   297  
   298  	if updatePseudoHeader {
   299  		var oldAddr tcpip.Address
   300  		if updateSRCFields {
   301  			oldAddr = n.SourceAddress()
   302  		} else {
   303  			oldAddr = n.DestinationAddress()
   304  		}
   305  
   306  		t.UpdateChecksumPseudoHeaderAddress(oldAddr, newAddr, fullChecksum)
   307  	}
   308  
   309  	if checksummableNetHeader, ok := n.(header.ChecksummableNetwork); ok {
   310  		if updateSRCFields {
   311  			checksummableNetHeader.SetSourceAddressWithChecksumUpdate(newAddr)
   312  		} else {
   313  			checksummableNetHeader.SetDestinationAddressWithChecksumUpdate(newAddr)
   314  		}
   315  	} else if updateSRCFields {
   316  		n.SetSourceAddress(newAddr)
   317  	} else {
   318  		n.SetDestinationAddress(newAddr)
   319  	}
   320  }