Add service proxy
This adds a service proxy based on nfproxy and changes to the service IP allocation to make it work.
Also adds support for masquerading outbound traffic for outbound network connectivity.
Test Plan:
Currently manually tested by creating an alpine pod and running 'apk add curl && curl -k https://192.168.188.1:443/'.
Will be covered later by CTS.
Bug: T810
X-Origin-Diff: phab/D580
GitOrigin-RevId: cace863fd8c2f045560f8abf84c40cc77bc275d4
diff --git a/core/internal/network/main.go b/core/internal/network/main.go
index ac9ce46..c92b21a 100644
--- a/core/internal/network/main.go
+++ b/core/internal/network/main.go
@@ -23,6 +23,9 @@
"net"
"os"
+ "github.com/google/nftables"
+ "github.com/google/nftables/expr"
+
"github.com/vishvananda/netlink"
"go.uber.org/zap"
"golang.org/x/sys/unix"
@@ -97,6 +100,13 @@
return nil
}
+// nfifname converts an interface name into 16 bytes padded with zeroes (for nftables)
+func nfifname(n string) []byte {
+ b := make([]byte, 16)
+ copy(b, []byte(n+"\x00"))
+ return b
+}
+
func (s *Service) useInterface(ctx context.Context, iface netlink.Link) error {
err := supervisor.Run(ctx, "dhcp", s.dhcp.Run(iface))
if err != nil {
@@ -115,6 +125,40 @@
s.logger.Warn("failed to add routes", zap.Error(err))
}
+ c := nftables.Conn{}
+
+ nat := c.AddTable(&nftables.Table{
+ Family: nftables.TableFamilyIPv4,
+ Name: "nat",
+ })
+
+ postrouting := c.AddChain(&nftables.Chain{
+ Name: "postrouting",
+ Hooknum: nftables.ChainHookPostrouting,
+ Priority: nftables.ChainPriorityNATSource,
+ Table: nat,
+ Type: nftables.ChainTypeNAT,
+ })
+
+ // Masquerade/SNAT all traffic going out of the external interface
+ c.AddRule(&nftables.Rule{
+ Table: nat,
+ Chain: postrouting,
+ Exprs: []expr.Any{
+ &expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},
+ &expr.Cmp{
+ Op: expr.CmpOpEq,
+ Register: 1,
+ Data: nfifname(iface.Attrs().Name),
+ },
+ &expr.Masq{},
+ },
+ })
+
+ if err := c.Flush(); err != nil {
+ panic(err)
+ }
+
return nil
}