mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
committed by
gVisor bot
parent
cb86d3ea02
commit
b9fe44808b
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user