netstack: support snat revision 2 targets

We now support all snat target versions. dnat targets will reuse the same
structs in a later CL.

PiperOrigin-RevId: 581455903
This commit is contained in:
Kevin Krakauer
2023-11-10 22:36:58 -08:00
committed by gVisor bot
parent cb86d3ea02
commit b9fe44808b
4 changed files with 117 additions and 0 deletions
+11
View File
@@ -413,6 +413,17 @@ type XTNATTargetV1 struct {
// SizeOfXTNATTargetV1 is the size of an XTNATTargetV1.
const SizeOfXTNATTargetV1 = SizeOfXTEntryTarget + SizeOfNFNATRange
// XTNATTargetV2 triggers NAT when reached.
//
// +marshal
type XTNATTargetV2 struct {
Target XTEntryTarget
Range NFNATRange2
}
// SizeOfXTNATTargetV2 is the size of an XTNATTargetV2.
const SizeOfXTNATTargetV2 = SizeOfXTEntryTarget + SizeOfNFNATRange2
// IPTGetinfo is the argument for the IPT_SO_GET_INFO sockopt. It corresponds
// to struct ipt_getinfo in include/uapi/linux/netfilter_ipv4/ip_tables.h.
//
+17
View File
@@ -275,3 +275,20 @@ type NFNATRange struct {
// SizeOfNFNATRange is the size of NFNATRange.
const SizeOfNFNATRange = 40
// NFNATRange2 corresponds to struct nf_nat_range2 in
// include/uapi/linux/netfilter/nf_nat.h.
//
// +marshal
type NFNATRange2 struct {
Flags uint32
MinAddr Inet6Addr
MaxAddr Inet6Addr
MinProto uint16 // Network byte order.
MaxProto uint16 // Network byte order.
BaseProto uint16 // Network byte order.
_ [6]byte
}
// SizeOfNFNATRange2 is the size of NFNATRange2.
const SizeOfNFNATRange2 = 48
+83
View File
@@ -197,3 +197,86 @@ func (st *snatTargetMakerR1) unmarshal(buf []byte, filter stack.IPHeaderFilter)
return &target, nil
}
type snatTargetMakerR2 struct {
NetworkProtocol tcpip.NetworkProtocolNumber
}
func (st *snatTargetMakerR2) id() targetID {
return targetID{
name: SNATTargetName,
networkProtocol: st.NetworkProtocol,
revision: 2,
}
}
func (*snatTargetMakerR2) marshal(target target) []byte {
st := target.(*snatTarget)
nt := linux.XTNATTargetV2{
Target: linux.XTEntryTarget{
TargetSize: linux.SizeOfXTNATTargetV1,
},
Range: linux.NFNATRange2{
Flags: linux.NF_NAT_RANGE_MAP_IPS | linux.NF_NAT_RANGE_PROTO_SPECIFIED,
},
}
copy(nt.Target.Name[:], SNATTargetName)
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 *snatTargetMakerR2) unmarshal(buf []byte, filter stack.IPHeaderFilter) (target, *syserr.Error) {
if size := linux.SizeOfXTNATTargetV2; len(buf) < size {
nflog("snatTargetMakerR2: buf has insufficient size (%d) for SNAT target (%d)", len(buf), size)
return nil, syserr.ErrInvalidArgument
}
if p := filter.Protocol; p != header.TCPProtocolNumber && p != header.UDPProtocolNumber {
nflog("snatTargetMakerR2: bad proto %d", p)
return nil, syserr.ErrInvalidArgument
}
var natRange linux.NFNATRange2
natRange.UnmarshalUnsafe(buf[linux.SizeOfXTEntryTarget:])
// TODO(gvisor.dev/issue/5697): Support port or address ranges.
if natRange.MinAddr != natRange.MaxAddr {
nflog("snatTargetMakerR2: MinAddr and MaxAddr are different")
return nil, syserr.ErrInvalidArgument
}
if natRange.MinProto != natRange.MaxProto {
nflog("snatTargetMakerR2: MinProto and MaxProto are different")
return nil, syserr.ErrInvalidArgument
}
if natRange.BaseProto != 0 {
nflog("snatTargetMakerR2: BaseProto is nonzero")
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("snatTargetMakerR2: invalid range flags %d", natRange.Flags)
return nil, syserr.ErrInvalidArgument
}
target := snatTarget{
SNATTarget: stack.SNATTarget{
NetworkProtocol: filter.NetworkProtocol(),
Port: ntohs(natRange.MinProto),
},
}
switch st.NetworkProtocol {
case header.IPv4ProtocolNumber:
target.SNATTarget.Addr = tcpip.AddrFrom4Slice(natRange.MinAddr[:4])
case header.IPv6ProtocolNumber:
target.SNATTarget.Addr = tcpip.AddrFrom16(natRange.MinAddr)
default:
panic(fmt.Sprintf("invalid protocol number: %d", st.NetworkProtocol))
}
return &target, nil
}
+6
View File
@@ -70,6 +70,12 @@ func init() {
registerTargetMaker(&snatTargetMakerR1{
NetworkProtocol: header.IPv6ProtocolNumber,
})
registerTargetMaker(&snatTargetMakerR2{
NetworkProtocol: header.IPv4ProtocolNumber,
})
registerTargetMaker(&snatTargetMakerR2{
NetworkProtocol: header.IPv6ProtocolNumber,
})
}
// The stack package provides some basic, useful targets for us. The following