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