| // Copyright 2019 The gVisor Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package stack |
| |
| import ( |
| "gvisor.dev/gvisor/pkg/log" |
| "gvisor.dev/gvisor/pkg/tcpip" |
| "gvisor.dev/gvisor/pkg/tcpip/header" |
| ) |
| |
| // AcceptTarget accepts packets. |
| type AcceptTarget struct{} |
| |
| // Action implements Target.Action. |
| func (AcceptTarget) Action(packet PacketBuffer) (RuleVerdict, int) { |
| return RuleAccept, 0 |
| } |
| |
| // DropTarget drops packets. |
| type DropTarget struct{} |
| |
| // Action implements Target.Action. |
| func (DropTarget) Action(packet PacketBuffer) (RuleVerdict, int) { |
| return RuleDrop, 0 |
| } |
| |
| // ErrorTarget logs an error and drops the packet. It represents a target that |
| // should be unreachable. |
| type ErrorTarget struct{} |
| |
| // Action implements Target.Action. |
| func (ErrorTarget) Action(packet PacketBuffer) (RuleVerdict, int) { |
| log.Debugf("ErrorTarget triggered.") |
| return RuleDrop, 0 |
| } |
| |
| // UserChainTarget marks a rule as the beginning of a user chain. |
| type UserChainTarget struct { |
| Name string |
| } |
| |
| // Action implements Target.Action. |
| func (UserChainTarget) Action(PacketBuffer) (RuleVerdict, int) { |
| panic("UserChainTarget should never be called.") |
| } |
| |
| // ReturnTarget returns from the current chain. If the chain is a built-in, the |
| // hook's underflow should be called. |
| type ReturnTarget struct{} |
| |
| // Action implements Target.Action. |
| func (ReturnTarget) Action(PacketBuffer) (RuleVerdict, int) { |
| return RuleReturn, 0 |
| } |
| |
| // RedirectTarget redirects the packet by modifying the destination port/IP. |
| // Min and Max values for IP and Ports in the struct indicate the range of |
| // values which can be used to redirect. |
| type RedirectTarget struct { |
| // TODO(gvisor.dev/issue/170): Other flags need to be added after |
| // we support them. |
| // RangeProtoSpecified flag indicates single port is specified to |
| // redirect. |
| RangeProtoSpecified bool |
| |
| // Min address used to redirect. |
| MinIP tcpip.Address |
| |
| // Max address used to redirect. |
| MaxIP tcpip.Address |
| |
| // Min port used to redirect. |
| MinPort uint16 |
| |
| // Max port used to redirect. |
| MaxPort uint16 |
| } |
| |
| // Action implements Target.Action. |
| // TODO(gvisor.dev/issue/170): Parse headers without copying. The current |
| // implementation only works for PREROUTING and calls pkt.Clone(), neither |
| // of which should be the case. |
| func (rt RedirectTarget) Action(pkt PacketBuffer) (RuleVerdict, int) { |
| newPkt := pkt.Clone() |
| |
| // Set network header. |
| headerView := newPkt.Data.First() |
| netHeader := header.IPv4(headerView) |
| newPkt.NetworkHeader = headerView[:header.IPv4MinimumSize] |
| |
| hlen := int(netHeader.HeaderLength()) |
| tlen := int(netHeader.TotalLength()) |
| newPkt.Data.TrimFront(hlen) |
| newPkt.Data.CapLength(tlen - hlen) |
| |
| // TODO(gvisor.dev/issue/170): Change destination address to |
| // loopback or interface address on which the packet was |
| // received. |
| |
| // TODO(gvisor.dev/issue/170): Check Flags in RedirectTarget if |
| // we need to change dest address (for OUTPUT chain) or ports. |
| switch protocol := netHeader.TransportProtocol(); protocol { |
| case header.UDPProtocolNumber: |
| var udpHeader header.UDP |
| if newPkt.TransportHeader != nil { |
| udpHeader = header.UDP(newPkt.TransportHeader) |
| } else { |
| if len(pkt.Data.First()) < header.UDPMinimumSize { |
| return RuleDrop, 0 |
| } |
| udpHeader = header.UDP(newPkt.Data.First()) |
| } |
| udpHeader.SetDestinationPort(rt.MinPort) |
| case header.TCPProtocolNumber: |
| var tcpHeader header.TCP |
| if newPkt.TransportHeader != nil { |
| tcpHeader = header.TCP(newPkt.TransportHeader) |
| } else { |
| if len(pkt.Data.First()) < header.TCPMinimumSize { |
| return RuleDrop, 0 |
| } |
| tcpHeader = header.TCP(newPkt.TransportHeader) |
| } |
| // TODO(gvisor.dev/issue/170): Need to recompute checksum |
| // and implement nat connection tracking to support TCP. |
| tcpHeader.SetDestinationPort(rt.MinPort) |
| default: |
| return RuleDrop, 0 |
| } |
| |
| return RuleAccept, 0 |
| } |