Skip to content

Commit de2484a

Browse files
kerumetogvisor-bot
authored andcommitted
Move network utility functions to a util package.
This change refactors common network utility functions used in iptables tests into a dedicated utils package to be shared with netfilter table tests. PiperOrigin-RevId: 799318149
1 parent 88b974c commit de2484a

File tree

8 files changed

+481
-432
lines changed

8 files changed

+481
-432
lines changed

test/iptables/BUILD

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ go_library(
2020
deps = [
2121
"//pkg/binary",
2222
"//pkg/hostarch",
23-
"//pkg/test/testutil",
23+
"//test/netutils",
2424
"@org_golang_x_sys//unix:go_default_library",
2525
],
2626
)
@@ -41,6 +41,7 @@ go_test(
4141
"//pkg/log",
4242
"//pkg/test/dockerutil",
4343
"//pkg/test/testutil",
44+
"//test/netutils",
4445
],
4546
)
4647

test/iptables/filter_input.go

Lines changed: 66 additions & 64 deletions
Large diffs are not rendered by default.

test/iptables/filter_output.go

Lines changed: 53 additions & 51 deletions
Large diffs are not rendered by default.

test/iptables/iptables_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"gvisor.dev/gvisor/pkg/log"
2727
"gvisor.dev/gvisor/pkg/test/dockerutil"
2828
"gvisor.dev/gvisor/pkg/test/testutil"
29+
"gvisor.dev/gvisor/test/netutils"
2930
)
3031

3132
// singleTest runs a TestCase. Each test follows a pattern:
@@ -469,7 +470,7 @@ func TestFilterAddrs(t *testing.T) {
469470
}
470471

471472
for _, tc := range tcs {
472-
if got := filterAddrs(tc.addrs, tc.ipv6); !slices.Equal(got, tc.want) {
473+
if got := netutils.FilterAddrs(tc.addrs, tc.ipv6); !slices.Equal(got, tc.want) {
473474
t.Errorf("%v with IPv6 %t: got %v, but wanted %v", tc.addrs, tc.ipv6, got, tc.want)
474475
}
475476
}

test/iptables/iptables_util.go

Lines changed: 0 additions & 265 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,8 @@
1515
package iptables
1616

1717
import (
18-
"context"
19-
"encoding/binary"
20-
"errors"
2118
"fmt"
22-
"net"
2319
"os/exec"
24-
"strings"
25-
"time"
26-
27-
"gvisor.dev/gvisor/pkg/test/testutil"
2820
)
2921

3022
// filterTable calls `ip{6}tables -t filter` with the given args.
@@ -68,260 +60,3 @@ func tableRules(ipv6 bool, table string, argsList [][]string) error {
6860
}
6961
return nil
7062
}
71-
72-
// listenUDP listens on a UDP port and returns nil if the first read from that
73-
// port is successful.
74-
func listenUDP(ctx context.Context, port int, ipv6 bool) error {
75-
_, err := listenUDPFrom(ctx, port, ipv6)
76-
return err
77-
}
78-
79-
// listenUDPFrom listens on a UDP port and returns the sender's UDP address if
80-
// the first read from that port is successful.
81-
func listenUDPFrom(ctx context.Context, port int, ipv6 bool) (*net.UDPAddr, error) {
82-
localAddr := net.UDPAddr{
83-
Port: port,
84-
}
85-
conn, err := net.ListenUDP(udpNetwork(ipv6), &localAddr)
86-
if err != nil {
87-
return nil, err
88-
}
89-
defer conn.Close()
90-
91-
type result struct {
92-
remoteAddr *net.UDPAddr
93-
err error
94-
}
95-
96-
ch := make(chan result)
97-
go func() {
98-
_, remoteAddr, err := conn.ReadFromUDP([]byte{0})
99-
ch <- result{remoteAddr, err}
100-
}()
101-
102-
select {
103-
case res := <-ch:
104-
return res.remoteAddr, res.err
105-
case <-ctx.Done():
106-
return nil, fmt.Errorf("timed out reading from %s: %w", &localAddr, ctx.Err())
107-
}
108-
}
109-
110-
// sendUDPLoop sends 1 byte UDP packets repeatedly to the IP and port specified
111-
// over a duration.
112-
func sendUDPLoop(ctx context.Context, ip net.IP, port int, ipv6 bool) error {
113-
remote := net.UDPAddr{
114-
IP: ip,
115-
Port: port,
116-
}
117-
conn, err := net.DialUDP(udpNetwork(ipv6), nil, &remote)
118-
if err != nil {
119-
return err
120-
}
121-
defer conn.Close()
122-
123-
for {
124-
// This may return an error (connection refused) if the remote
125-
// hasn't started listening yet or they're dropping our
126-
// packets. So we ignore Write errors and depend on the remote
127-
// to report a failure if it doesn't get a packet it needs.
128-
conn.Write([]byte{0})
129-
select {
130-
case <-ctx.Done():
131-
// Being cancelled or timing out isn't an error, as we
132-
// cannot tell with UDP whether we succeeded.
133-
return nil
134-
// Continue looping.
135-
case <-time.After(200 * time.Millisecond):
136-
}
137-
}
138-
}
139-
140-
// listenTCP listens for connections on a TCP port, and returns nil if a
141-
// connection is established.
142-
func listenTCP(ctx context.Context, port int, ipv6 bool) error {
143-
_, err := listenTCPFrom(ctx, port, ipv6)
144-
return err
145-
}
146-
147-
// listenTCP listens for connections on a TCP port, and returns the remote
148-
// TCP address if a connection is established.
149-
func listenTCPFrom(ctx context.Context, port int, ipv6 bool) (net.Addr, error) {
150-
localAddr := net.TCPAddr{
151-
Port: port,
152-
}
153-
154-
// Starts listening on port.
155-
lConn, err := net.ListenTCP(tcpNetwork(ipv6), &localAddr)
156-
if err != nil {
157-
return nil, err
158-
}
159-
defer lConn.Close()
160-
161-
type result struct {
162-
remoteAddr net.Addr
163-
err error
164-
}
165-
166-
// Accept connections on port.
167-
ch := make(chan result)
168-
go func() {
169-
conn, err := lConn.AcceptTCP()
170-
var remoteAddr net.Addr
171-
if err == nil {
172-
remoteAddr = conn.RemoteAddr()
173-
}
174-
ch <- result{remoteAddr, err}
175-
conn.Close()
176-
}()
177-
178-
select {
179-
case res := <-ch:
180-
return res.remoteAddr, res.err
181-
case <-ctx.Done():
182-
return nil, fmt.Errorf("timed out waiting for a connection at %s: %w", &localAddr, ctx.Err())
183-
}
184-
}
185-
186-
// connectTCP connects to the given IP and port from an ephemeral local address.
187-
func connectTCP(ctx context.Context, ip net.IP, port int, ipv6 bool) error {
188-
contAddr := net.TCPAddr{
189-
IP: ip,
190-
Port: port,
191-
}
192-
// The container may not be listening when we first connect, so retry
193-
// upon error.
194-
callback := func() error {
195-
var d net.Dialer
196-
conn, err := d.DialContext(ctx, tcpNetwork(ipv6), contAddr.String())
197-
if conn != nil {
198-
conn.Close()
199-
}
200-
return err
201-
}
202-
if err := testutil.PollContext(ctx, callback); err != nil {
203-
return fmt.Errorf("timed out waiting to connect IP on port %v, most recent error: %w", port, err)
204-
}
205-
206-
return nil
207-
}
208-
209-
// localAddrs returns a list of local network interface addresses. When ipv6 is
210-
// true, only IPv6 addresses are returned. Otherwise only IPv4 addresses are
211-
// returned.
212-
func localAddrs(ipv6 bool) ([]string, error) {
213-
addrs, err := net.InterfaceAddrs()
214-
if err != nil {
215-
return nil, err
216-
}
217-
addrStrs := make([]string, 0, len(addrs))
218-
for _, addr := range addrs {
219-
// Add only IPv4 or only IPv6 addresses.
220-
parts := strings.Split(addr.String(), "/")
221-
if len(parts) != 2 {
222-
return nil, fmt.Errorf("bad interface address: %q", addr.String())
223-
}
224-
if isIPv6 := net.ParseIP(parts[0]).To4() == nil; isIPv6 == ipv6 {
225-
addrStrs = append(addrStrs, addr.String())
226-
}
227-
}
228-
return filterAddrs(addrStrs, ipv6), nil
229-
}
230-
231-
func filterAddrs(addrs []string, ipv6 bool) []string {
232-
addrStrs := make([]string, 0, len(addrs))
233-
for _, addr := range addrs {
234-
// Add only IPv4 or only IPv6 addresses.
235-
parts := strings.Split(addr, "/")
236-
if isIPv6 := net.ParseIP(parts[0]).To4() == nil; isIPv6 == ipv6 {
237-
addrStrs = append(addrStrs, parts[0])
238-
}
239-
}
240-
return addrStrs
241-
}
242-
243-
// getInterfaceName returns the name of the interface other than loopback.
244-
func getInterfaceName() (string, bool) {
245-
iface, ok := getNonLoopbackInterface()
246-
if !ok {
247-
return "", false
248-
}
249-
return iface.Name, true
250-
}
251-
252-
func getInterfaceAddrs(ipv6 bool) ([]net.IP, error) {
253-
iface, ok := getNonLoopbackInterface()
254-
if !ok {
255-
return nil, errors.New("no non-loopback interface found")
256-
}
257-
addrs, err := iface.Addrs()
258-
if err != nil {
259-
return nil, err
260-
}
261-
262-
// Get only IPv4 or IPv6 addresses.
263-
ips := make([]net.IP, 0, len(addrs))
264-
for _, addr := range addrs {
265-
parts := strings.Split(addr.String(), "/")
266-
var ip net.IP
267-
// To16() returns IPv4 addresses as IPv4-mapped IPv6 addresses.
268-
// So we check whether To4() returns nil to test whether the
269-
// address is v4 or v6.
270-
if v4 := net.ParseIP(parts[0]).To4(); ipv6 && v4 == nil {
271-
ip = net.ParseIP(parts[0]).To16()
272-
} else {
273-
ip = v4
274-
}
275-
if ip != nil {
276-
ips = append(ips, ip)
277-
}
278-
}
279-
return ips, nil
280-
}
281-
282-
func getNonLoopbackInterface() (net.Interface, bool) {
283-
if interfaces, err := net.Interfaces(); err == nil {
284-
for _, intf := range interfaces {
285-
if intf.Name != "lo" {
286-
return intf, true
287-
}
288-
}
289-
}
290-
return net.Interface{}, false
291-
}
292-
293-
func htons(x uint16) uint16 {
294-
buf := make([]byte, 2)
295-
binary.BigEndian.PutUint16(buf, x)
296-
return binary.LittleEndian.Uint16(buf)
297-
}
298-
299-
func localIP(ipv6 bool) string {
300-
if ipv6 {
301-
return "::1"
302-
}
303-
return "127.0.0.1"
304-
}
305-
306-
func nowhereIP(ipv6 bool) string {
307-
if ipv6 {
308-
return "2001:db8::1"
309-
}
310-
return "192.0.2.1"
311-
}
312-
313-
// udpNetwork returns an IPv6 or IPv6 UDP network argument to net.Dial.
314-
func udpNetwork(ipv6 bool) string {
315-
if ipv6 {
316-
return "udp6"
317-
}
318-
return "udp4"
319-
}
320-
321-
// tcpNetwork returns an IPv6 or IPv6 TCP network argument to net.Dial.
322-
func tcpNetwork(ipv6 bool) string {
323-
if ipv6 {
324-
return "tcp6"
325-
}
326-
return "tcp4"
327-
}

0 commit comments

Comments
 (0)