iptables_targets.go raw

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