netstack: iptables DNAT revision 2

With this change, we support all the DNS rules intalled by Docker when using
custom networks.

PiperOrigin-RevId: 582073741
This commit is contained in:
Kevin Krakauer
2023-11-13 13:57:05 -08:00
committed by gVisor bot
parent 7a918a4292
commit 8657560bd1
3 changed files with 93 additions and 3 deletions
+83
View File
@@ -197,3 +197,86 @@ func (st *dnatTargetMakerR1) unmarshal(buf []byte, filter stack.IPHeaderFilter)
return &target, nil
}
type dnatTargetMakerR2 struct {
NetworkProtocol tcpip.NetworkProtocolNumber
}
func (st *dnatTargetMakerR2) id() targetID {
return targetID{
name: DNATTargetName,
networkProtocol: st.NetworkProtocol,
revision: 2,
}
}
func (*dnatTargetMakerR2) marshal(target target) []byte {
st := target.(*dnatTarget)
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[:], 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 *dnatTargetMakerR2) unmarshal(buf []byte, filter stack.IPHeaderFilter) (target, *syserr.Error) {
if size := linux.SizeOfXTNATTargetV2; len(buf) < size {
nflog("dnatTargetMakerR2: 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("dnatTargetMakerR2: 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("dnatTargetMakerR2: MinAddr and MaxAddr are different")
return nil, syserr.ErrInvalidArgument
}
if natRange.MinProto != natRange.MaxProto {
nflog("dnatTargetMakerR2: MinProto and MaxProto are different")
return nil, syserr.ErrInvalidArgument
}
if natRange.BaseProto != 0 {
nflog("dnatTargetMakerR2: 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("dnatTargetMakerR2: 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
@@ -89,6 +89,12 @@ func init() {
registerTargetMaker(&dnatTargetMakerR1{
NetworkProtocol: header.IPv6ProtocolNumber,
})
registerTargetMaker(&dnatTargetMakerR2{
NetworkProtocol: header.IPv4ProtocolNumber,
})
registerTargetMaker(&dnatTargetMakerR2{
NetworkProtocol: header.IPv6ProtocolNumber,
})
}
// The stack package provides some basic, useful targets for us. The following
+4 -3
View File
@@ -931,7 +931,8 @@ const (
snatPort = 43
)
// NATPostSNATUDP tests that the source port/IP in the packets are modified as expected.
// NATPostSNATUDP tests that the source port/IP in the packets are modified as
// expected. It tests the latest-implemented revision of the SNAT target.
type NATPostSNATUDP struct{ localCase }
var _ TestCase = (*NATPostSNATUDP)(nil)
@@ -978,7 +979,7 @@ func (*NATPostSNATUDP) LocalAction(ctx context.Context, ip net.IP, ipv6 bool) er
}
// NATPostSNATTCP tests that the source port/IP in the packets are modified as
// expected.
// expected. It tests the latest-implemented revision of the SNAT target.
type NATPostSNATTCP struct{ localCase }
var _ TestCase = (*NATPostSNATTCP)(nil)
@@ -1038,7 +1039,7 @@ func (*NATPostSNATTCP) LocalAction(ctx context.Context, ip net.IP, ipv6 bool) er
}
// NATOutDNAT tests that the source port/IP in the packets are modified as
// expected.
// expected. It tests the latest-implemented revision of the DNAT target.
type NATOutDNAT struct{ containerCase }
var _ TestCase = (*NATOutDNAT)(nil)