summaryrefslogtreecommitdiffhomepage
path: root/test/iptables/iptables_util.go
diff options
context:
space:
mode:
authorToshi Kikuchi <toshik@google.com>2021-04-09 21:09:47 -0700
committergVisor bot <gvisor-bot@google.com>2021-04-09 21:11:26 -0700
commitd1edabdca016b9d80295855a3ce6d2816486d65c (patch)
tree9e9827ed0ff58ada2beab7605366d5c881404861 /test/iptables/iptables_util.go
parentea7faa50579d3d76c6cbb1f7ffba4e16eebf1885 (diff)
iptables: support postrouting hook and SNAT target
The current SNAT implementation has several limitations: - SNAT source port has to be specified. It is not optional. - SNAT source port range is not supported. - SNAT for UDP is a one-way translation. No response packets are handled (because conntrack doesn't support UDP currently). - SNAT and REDIRECT can't work on the same connection. Fixes #5489 PiperOrigin-RevId: 367750325
Diffstat (limited to 'test/iptables/iptables_util.go')
-rw-r--r--test/iptables/iptables_util.go61
1 files changed, 45 insertions, 16 deletions
diff --git a/test/iptables/iptables_util.go b/test/iptables/iptables_util.go
index bba17b894..4590e169d 100644
--- a/test/iptables/iptables_util.go
+++ b/test/iptables/iptables_util.go
@@ -69,29 +69,41 @@ func tableRules(ipv6 bool, table string, argsList [][]string) error {
return nil
}
-// listenUDP listens on a UDP port and returns the value of net.Conn.Read() for
-// the first read on that port.
+// listenUDP listens on a UDP port and returns nil if the first read from that
+// port is successful.
func listenUDP(ctx context.Context, port int, ipv6 bool) error {
+ _, err := listenUDPFrom(ctx, port, ipv6)
+ return err
+}
+
+// listenUDPFrom listens on a UDP port and returns the sender's UDP address if
+// the first read from that port is successful.
+func listenUDPFrom(ctx context.Context, port int, ipv6 bool) (*net.UDPAddr, error) {
localAddr := net.UDPAddr{
Port: port,
}
conn, err := net.ListenUDP(udpNetwork(ipv6), &localAddr)
if err != nil {
- return err
+ return nil, err
}
defer conn.Close()
- ch := make(chan error)
+ type result struct {
+ remoteAddr *net.UDPAddr
+ err error
+ }
+
+ ch := make(chan result)
go func() {
- _, err = conn.Read([]byte{0})
- ch <- err
+ _, remoteAddr, err := conn.ReadFromUDP([]byte{0})
+ ch <- result{remoteAddr, err}
}()
select {
- case err := <-ch:
- return err
+ case res := <-ch:
+ return res.remoteAddr, res.err
case <-ctx.Done():
- return ctx.Err()
+ return nil, fmt.Errorf("timed out reading from %s: %w", &localAddr, ctx.Err())
}
}
@@ -125,8 +137,16 @@ func sendUDPLoop(ctx context.Context, ip net.IP, port int, ipv6 bool) error {
}
}
-// listenTCP listens for connections on a TCP port.
+// listenTCP listens for connections on a TCP port, and returns nil if a
+// connection is established.
func listenTCP(ctx context.Context, port int, ipv6 bool) error {
+ _, err := listenTCPFrom(ctx, port, ipv6)
+ return err
+}
+
+// listenTCP listens for connections on a TCP port, and returns the remote
+// TCP address if a connection is established.
+func listenTCPFrom(ctx context.Context, port int, ipv6 bool) (net.Addr, error) {
localAddr := net.TCPAddr{
Port: port,
}
@@ -134,23 +154,32 @@ func listenTCP(ctx context.Context, port int, ipv6 bool) error {
// Starts listening on port.
lConn, err := net.ListenTCP(tcpNetwork(ipv6), &localAddr)
if err != nil {
- return err
+ return nil, err
}
defer lConn.Close()
+ type result struct {
+ remoteAddr net.Addr
+ err error
+ }
+
// Accept connections on port.
- ch := make(chan error)
+ ch := make(chan result)
go func() {
conn, err := lConn.AcceptTCP()
- ch <- err
+ var remoteAddr net.Addr
+ if err == nil {
+ remoteAddr = conn.RemoteAddr()
+ }
+ ch <- result{remoteAddr, err}
conn.Close()
}()
select {
- case err := <-ch:
- return err
+ case res := <-ch:
+ return res.remoteAddr, res.err
case <-ctx.Done():
- return fmt.Errorf("timed out waiting for a connection at %#v: %w", localAddr, ctx.Err())
+ return nil, fmt.Errorf("timed out waiting for a connection at %s: %w", &localAddr, ctx.Err())
}
}