diff options
-rw-r--r-- | pkg/sentry/socket/netfilter/netfilter.go | 14 | ||||
-rw-r--r-- | pkg/tcpip/iptables/targets.go | 55 | ||||
-rw-r--r-- | pkg/tcpip/iptables/types.go | 2 |
3 files changed, 53 insertions, 18 deletions
diff --git a/pkg/sentry/socket/netfilter/netfilter.go b/pkg/sentry/socket/netfilter/netfilter.go index f68a2260d..c8a9e67b8 100644 --- a/pkg/sentry/socket/netfilter/netfilter.go +++ b/pkg/sentry/socket/netfilter/netfilter.go @@ -292,9 +292,9 @@ func marshalRedirectTarget() []byte { }, } copy(target.Target.Name[:], redirectTargetName) - + ret := make([]byte, 0, linux.SizeOfXTRedirectTarget) - return binary.Marshal(ret, usermem.ByteOrder, target) + return binary.Marshal(ret, usermem.ByteOrder, target) } func marshalJumpTarget(jt JumpTarget) []byte { @@ -670,15 +670,21 @@ func parseTarget(filter iptables.IPHeaderFilter, optVal []byte) (iptables.Target // TODO(gvisor.dev/issue/170): Check if the flags are valid. // Also check if we need to map ports or IP. - // For now, redirect target only supports dest port change. + // For now, redirect target only supports destination port change. + // Port range and IP range are not supported yet. if nfRange.RangeIPV4.Flags&linux.NF_NAT_RANGE_PROTO_SPECIFIED == 0 { return nil, fmt.Errorf("netfilter.SetEntries: invalid argument.") } - target.Flags = nfRange.RangeIPV4.Flags + target.RangeProtoSpecified = true target.MinIP = tcpip.Address(nfRange.RangeIPV4.MinIP[:]) target.MaxIP = tcpip.Address(nfRange.RangeIPV4.MaxIP[:]) + // TODO(gvisor.dev/issue/170): Port range is not supported yet. + if nfRange.RangeIPV4.MinPort != nfRange.RangeIPV4.MaxPort { + return nil, fmt.Errorf("netfilter.SetEntries: invalid argument.") + } + // Convert port from big endian to little endian. port := make([]byte, 2) binary.BigEndian.PutUint16(port, nfRange.RangeIPV4.MinPort) diff --git a/pkg/tcpip/iptables/targets.go b/pkg/tcpip/iptables/targets.go index 96318118c..ae5af7c53 100644 --- a/pkg/tcpip/iptables/targets.go +++ b/pkg/tcpip/iptables/targets.go @@ -69,8 +69,11 @@ func (ReturnTarget) Action(tcpip.PacketBuffer) (RuleVerdict, int) { // 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 { - // Flags to check if the redirect is for address or ports. - Flags uint32 + // TODO(gvisor.dev/issue/170): Other flags need to be aded after + // we support them. + // RangeProtoSpecified flag indicates single port is specified to + // redirect. + RangeProtoSpecified bool // Min address used to redirect. MinIP tcpip.Address @@ -86,30 +89,56 @@ type RedirectTarget struct { } // 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 tcpip.PacketBuffer) (RuleVerdict, int) { - headerView := pkt.Data.First() + newPkt := pkt.Clone() - // Network header should be set. + // Set network header. + headerView := newPkt.Data.First() netHeader := header.IPv4(headerView) - if netHeader == nil { - return RuleDrop, 0 - } + newPkt.NetworkHeader = headerView[:netHeader.HeaderLength()] - // TODO(gvisor.dev/issue/170): Check Flags in RedirectTarget if - // we need to change dest address (for OUTPUT chain) or ports. 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: - udp := header.UDP(headerView[hlen:]) - udp.SetDestinationPort(rt.MinPort) + 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. - tcp := header.TCP(headerView[hlen:]) - tcp.SetDestinationPort(rt.MinPort) + tcpHeader.SetDestinationPort(rt.MinPort) default: return RuleDrop, 0 } + return RuleAccept, 0 } diff --git a/pkg/tcpip/iptables/types.go b/pkg/tcpip/iptables/types.go index 9c2ad2d46..7d032fd23 100644 --- a/pkg/tcpip/iptables/types.go +++ b/pkg/tcpip/iptables/types.go @@ -163,6 +163,6 @@ type Matcher interface { type Target interface { // Action takes an action on the packet and returns a verdict on how // traversal should (or should not) continue. If the return value is - // Jump, it also returns the name of the chain to jump to. + // Jump, it also returns the index of the rule to jump to. Action(packet tcpip.PacketBuffer) (RuleVerdict, int) } |