Skip to content

Commit

Permalink
netstack: iptables DNAT revision 1 support
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 581537255
  • Loading branch information
kevinGC authored and gvisor-bot committed Nov 11, 2023
1 parent 62175de commit a69a483
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
81 changes: 81 additions & 0 deletions pkg/sentry/socket/netfilter/dnat.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package netfilter

import (
"fmt"

"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/marshal"
"gvisor.dev/gvisor/pkg/syserr"
Expand Down Expand Up @@ -116,3 +118,82 @@ func (*dnatTargetMakerV4) unmarshal(buf []byte, filter stack.IPHeaderFilter) (ta

return &target, nil
}

type dnatTargetMakerR1 struct {
NetworkProtocol tcpip.NetworkProtocolNumber
}

func (st *dnatTargetMakerR1) id() targetID {
return targetID{
name: DNATTargetName,
networkProtocol: st.NetworkProtocol,
revision: 1,
}
}

func (*dnatTargetMakerR1) marshal(target target) []byte {
st := target.(*dnatTarget)
nt := linux.XTNATTargetV1{
Target: linux.XTEntryTarget{
TargetSize: linux.SizeOfXTNATTargetV1,
},
Range: linux.NFNATRange{
Flags: linux.NF_NAT_RANGE_MAP_IPS | linux.NF_NAT_RANGE_PROTO_SPECIFIED,
},
}
copy(nt.Target.Name[:], DNATTargetName)
copy(nt.Range.MinAddr[:], st.Addr.AsSlice())
copy(nt.Range.MaxAddr[:], st.Addr.AsSlice())
nt.Range.MinProto = htons(st.Port)
nt.Range.MaxProto = nt.Range.MinProto

return marshal.Marshal(&nt)
}

func (st *dnatTargetMakerR1) unmarshal(buf []byte, filter stack.IPHeaderFilter) (target, *syserr.Error) {
if size := linux.SizeOfXTNATTargetV1; len(buf) < size {
nflog("dnatTargetMakerR1: buf has insufficient size (%d) for DNAT target (%d)", len(buf), size)
return nil, syserr.ErrInvalidArgument
}

if p := filter.Protocol; p != header.TCPProtocolNumber && p != header.UDPProtocolNumber {
nflog("dnatTargetMakerR1: bad proto %d", p)
return nil, syserr.ErrInvalidArgument
}

var natRange linux.NFNATRange
natRange.UnmarshalUnsafe(buf[linux.SizeOfXTEntryTarget:])

// TODO(gvisor.dev/issue/5697): Support port or address ranges.
if natRange.MinAddr != natRange.MaxAddr {
nflog("dnatTargetMakerR1: MinAddr and MaxAddr are different")
return nil, syserr.ErrInvalidArgument
}
if natRange.MinProto != natRange.MaxProto {
nflog("dnatTargetMakerR1: MinProto and MaxProto are different")
return nil, syserr.ErrInvalidArgument
}

// TODO(gvisor.dev/issue/5698): Support other NF_NAT_RANGE flags.
if natRange.Flags != linux.NF_NAT_RANGE_MAP_IPS|linux.NF_NAT_RANGE_PROTO_SPECIFIED {
nflog("dnatTargetMakerR1: invalid range flags %d", natRange.Flags)
return nil, syserr.ErrInvalidArgument
}

target := dnatTarget{
DNATTarget: stack.DNATTarget{
NetworkProtocol: filter.NetworkProtocol(),
Port: ntohs(natRange.MinProto),
},
}
switch st.NetworkProtocol {
case header.IPv4ProtocolNumber:
target.DNATTarget.Addr = tcpip.AddrFrom4Slice(natRange.MinAddr[:4])
case header.IPv6ProtocolNumber:
target.DNATTarget.Addr = tcpip.AddrFrom16(natRange.MinAddr)
default:
panic(fmt.Sprintf("invalid protocol number: %d", st.NetworkProtocol))
}

return &target, nil
}
6 changes: 6 additions & 0 deletions pkg/sentry/socket/netfilter/targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ func init() {
registerTargetMaker(&dnatTargetMakerV4{
NetworkProtocol: header.IPv4ProtocolNumber,
})
registerTargetMaker(&dnatTargetMakerR1{
NetworkProtocol: header.IPv4ProtocolNumber,
})
registerTargetMaker(&dnatTargetMakerR1{
NetworkProtocol: header.IPv6ProtocolNumber,
})
}

// The stack package provides some basic, useful targets for us. The following
Expand Down

0 comments on commit a69a483

Please sign in to comment.