An embedder that runs untrusted workloads in the guest, and wants to hold them to an allow list of destinations on the host side, has no point where it can refuse a connection the forwarders open for the guest, or learn the addresses the embedded DNS server resolved. This adds two optional hooks to types.Configuration:
DialFilter func(network, address string) erroris called by the TCP, UDP and ICMP forwarders with the destination after NAT translation, before they dial. A non-nil error refuses the connection: TCP answers the guest with a reset, UDP and ICMP are dropped.DNSObserver func(name string, ips []net.IP)is called by the DNS server with the IPv4 addresses of every A answer it takes from the upstream resolver, before the answer is sent, so a connection the guest opens after the lookup already finds its address allowed.
Both are yaml:"-" and nil by default, which leaves current behaviour unchanged. One thing to note for review: forwarder.TCP, forwarder.UDP and forwarder.ICMP take the filter as a new trailing parameter, so a caller of those functions outside pkg/virtualnetwork needs to pass nil. If an options struct or a setter would suit the project better, I can change it.
The change is split in two commits, one per hook, each building on its own. pkg/services/forwarder and pkg/services/dns gain tests for the refusal and the observed answers. make cross-lint and go test ./pkg/... pass; the VM-based suites were not run locally.
[APPROVALNOTIFIER] This PR is NOT APPROVED
This pull-request has been approved by: gorkem Once this PR has been reviewed and has the lgtm label, please assign cfergeau for approval. For more information see the Code Review Process.
The full list of commands accepted by this bot can be found here.
Approvers can indicate their approval by writing
/approvein a comment Approvers can cancel approval by writing/approve cancelin a comment