netstack: iptables DNAT revision 1 support

PiperOrigin-RevId: 581537255
This commit is contained in:
Kevin Krakauer
2023-11-11 07:00:54 -08:00
committed by gVisor bot
parent 62175dea49
commit a69a4835f2
2 changed files with 87 additions and 0 deletions
+81
View File
@@ -15,6 +15,8 @@
package netfilter
import (
"fmt"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/marshal"
"gvisor.dev/gvisor/pkg/syserr"
@@ -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
View File
@@ -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