From ec18c6bcf9760b8a6a8eaed61ee0f6cb915b9466 Mon Sep 17 00:00:00 2001 From: Arthur Sfez Date: Mon, 20 Dec 2021 10:08:15 -0800 Subject: [PATCH] Add default TTL test for udp and tcp endpoints Simplify the retrieval of the default TTL and include multicast flow in the UDP SetTTL tests. Add IPv6 protocol coverage for the TCP TTL tests PiperOrigin-RevId: 417429943 --- pkg/tcpip/transport/tcp/tcp_test.go | 91 +++++++++++++++++++++++++---- pkg/tcpip/transport/udp/udp_test.go | 55 ++++++++--------- 2 files changed, 106 insertions(+), 40 deletions(-) diff --git a/pkg/tcpip/transport/tcp/tcp_test.go b/pkg/tcpip/transport/tcp/tcp_test.go index 0566e53a3..0b88480ef 100644 --- a/pkg/tcpip/transport/tcp/tcp_test.go +++ b/pkg/tcpip/transport/tcp/tcp_test.go @@ -3403,33 +3403,104 @@ func TestSendGreaterThanMTU(t *testing.T) { testBrokenUpWrite(t, c, maxPayload) } -func TestSetTTL(t *testing.T) { - for _, wantTTL := range []uint8{1, 2, 50, 64, 128, 254, 255} { - t.Run(fmt.Sprintf("TTL:%d", wantTTL), func(t *testing.T) { +func TestDefaultTTL(t *testing.T) { + for _, test := range []struct { + name string + protoNum tcpip.NetworkProtocolNumber + addr tcpip.Address + }{ + {"ipv4", ipv4.ProtocolNumber, context.TestAddr}, + {"ipv6", ipv6.ProtocolNumber, context.TestV6Addr}, + } { + t.Run(fmt.Sprint(test.name), func(t *testing.T) { c := context.New(t, 65535) defer c.Cleanup() var err tcpip.Error - c.EP, err = c.Stack().NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &waiter.Queue{}) + c.EP, err = c.Stack().NewEndpoint(tcp.ProtocolNumber, test.protoNum, &waiter.Queue{}) if err != nil { t.Fatalf("NewEndpoint failed: %s", err) } - if err := c.EP.SetSockOptInt(tcpip.TTLOption, int(wantTTL)); err != nil { - t.Fatalf("SetSockOptInt(TTLOption, %d) failed: %s", wantTTL, err) + proto := c.Stack().NetworkProtocolInstance(test.protoNum) + if proto == nil { + t.Fatalf("c.s.NetworkProtocolInstance(flow.netProto()) did not return a protocol") + } + + var initialDefaultTTL tcpip.DefaultTTLOption + if err := proto.Option(&initialDefaultTTL); err != nil { + t.Fatalf("proto.Option(&initialDefaultTTL) (%T) failed: %s", initialDefaultTTL, err) } { - err := c.EP.Connect(tcpip.FullAddress{Addr: context.TestAddr, Port: context.TestPort}) + err := c.EP.Connect(tcpip.FullAddress{Addr: test.addr, Port: context.TestPort}) if d := cmp.Diff(&tcpip.ErrConnectStarted{}, err); d != "" { t.Fatalf("c.EP.Connect(...) mismatch (-want +got):\n%s", d) } } - // Receive SYN packet. - b := c.GetPacket() + checkTTL := func(ttl uint8) { + if test.protoNum == ipv4.ProtocolNumber { + checker.IPv4(t, c.GetPacket(), checker.TTL(ttl)) + } else { + checker.IPv6(t, c.GetV6Packet(), checker.TTL(ttl)) + } + } - checker.IPv4(t, b, checker.TTL(wantTTL)) + // Receive SYN packet. + checkTTL(uint8(initialDefaultTTL)) + + newDefaultTTL := tcpip.DefaultTTLOption(initialDefaultTTL + 1) + if err := proto.SetOption(&newDefaultTTL); err != nil { + t.Fatalf("proto.SetOption(&%T(%d))) failed: %s", newDefaultTTL, newDefaultTTL, err) + } + + // Receive retransmitted SYN packet. + checkTTL(uint8(newDefaultTTL)) + }) + } +} + +func TestSetTTL(t *testing.T) { + for _, test := range []struct { + name string + protoNum tcpip.NetworkProtocolNumber + addr tcpip.Address + }{ + {"ipv4", ipv4.ProtocolNumber, context.TestAddr}, + {"ipv6", ipv6.ProtocolNumber, context.TestV6Addr}, + } { + t.Run(fmt.Sprint(test.name), func(t *testing.T) { + for _, wantTTL := range []uint8{1, 2, 50, 64, 128, 254, 255} { + t.Run(fmt.Sprintf("TTL:%d", wantTTL), func(t *testing.T) { + c := context.New(t, 65535) + defer c.Cleanup() + + var err tcpip.Error + c.EP, err = c.Stack().NewEndpoint(tcp.ProtocolNumber, test.protoNum, &waiter.Queue{}) + if err != nil { + t.Fatalf("NewEndpoint failed: %s", err) + } + + if err := c.EP.SetSockOptInt(tcpip.TTLOption, int(wantTTL)); err != nil { + t.Fatalf("SetSockOptInt(TTLOption, %d) failed: %s", wantTTL, err) + } + + { + err := c.EP.Connect(tcpip.FullAddress{Addr: test.addr, Port: context.TestPort}) + if d := cmp.Diff(&tcpip.ErrConnectStarted{}, err); d != "" { + t.Fatalf("c.EP.Connect(...) mismatch (-want +got):\n%s", d) + } + } + + // Receive SYN packet. + if test.protoNum == ipv4.ProtocolNumber { + checker.IPv4(t, c.GetPacket(), checker.TTL(wantTTL)) + } else { + checker.IPv6(t, c.GetV6Packet(), checker.TTL(wantTTL)) + } + }) + } }) } } diff --git a/pkg/tcpip/transport/udp/udp_test.go b/pkg/tcpip/transport/udp/udp_test.go index 993acf109..99d6ed1ba 100644 --- a/pkg/tcpip/transport/udp/udp_test.go +++ b/pkg/tcpip/transport/udp/udp_test.go @@ -287,6 +287,13 @@ func (flow testFlow) isReverseMulticast() bool { } } +func (flow testFlow) ttlOption() tcpip.SockOptInt { + if flow.isMulticast() { + return tcpip.MulticastTTLOption + } + return tcpip.TTLOption +} + type testContext struct { t *testing.T linkEP *channel.Endpoint @@ -1608,48 +1615,35 @@ func (*testInterface) Enabled() bool { return true } -func TestTTL(t *testing.T) { - for _, flow := range []testFlow{unicastV4, unicastV4in6, unicastV6, unicastV6Only, multicastV4, multicastV4in6, multicastV6, broadcast, broadcastIn6} { +func TestNonMulticastDefaultTTL(t *testing.T) { + for _, flow := range []testFlow{unicastV4, unicastV4in6, unicastV6, unicastV6Only, broadcast, broadcastIn6} { t.Run(fmt.Sprintf("flow:%s", flow), func(t *testing.T) { c := newDualTestContext(t, defaultMTU) defer c.cleanup() c.createEndpointForFlow(flow) - - const multicastTTL = 42 - if err := c.ep.SetSockOptInt(tcpip.MulticastTTLOption, multicastTTL); err != nil { - c.t.Fatalf("SetSockOptInt failed: %s", err) + proto := c.s.NetworkProtocolInstance(flow.netProto()) + if proto == nil { + t.Fatalf("c.s.NetworkProtocolInstance(flow.netProto()) did not return a protocol") } - var wantTTL uint8 - if flow.isMulticast() { - wantTTL = multicastTTL - } else { - var p stack.NetworkProtocolFactory - var n tcpip.NetworkProtocolNumber - if flow.isV4() { - p = ipv4.NewProtocol - n = ipv4.ProtocolNumber - } else { - p = ipv6.NewProtocol - n = ipv6.ProtocolNumber - } - s := stack.New(stack.Options{ - NetworkProtocols: []stack.NetworkProtocolFactory{p}, - Clock: &faketime.NullClock{}, - }) - ep := s.NetworkProtocolInstance(n).NewEndpoint(&testInterface{}, nil) - wantTTL = ep.DefaultTTL() - ep.Close() + var initialDefaultTTL tcpip.DefaultTTLOption + if err := proto.Option(&initialDefaultTTL); err != nil { + t.Fatalf("proto.Option(&initialDefaultTTL) (%T) failed: %s", initialDefaultTTL, err) } + testWrite(c, flow, checker.TTL(uint8(initialDefaultTTL))) - testWrite(c, flow, checker.TTL(wantTTL)) + newDefaultTTL := tcpip.DefaultTTLOption(initialDefaultTTL + 1) + if err := proto.SetOption(&newDefaultTTL); err != nil { + c.t.Fatalf("proto.SetOption(&%T(%d))) failed: %s", newDefaultTTL, newDefaultTTL, err) + } + testWrite(c, flow, checker.TTL(uint8(newDefaultTTL))) }) } } func TestSetTTL(t *testing.T) { - for _, flow := range []testFlow{unicastV4, unicastV4in6, unicastV6, unicastV6Only, broadcast, broadcastIn6} { + for _, flow := range []testFlow{unicastV4, unicastV4in6, unicastV6, unicastV6Only, multicastV4, multicastV4in6, multicastV6, broadcast, broadcastIn6} { t.Run(fmt.Sprintf("flow:%s", flow), func(t *testing.T) { for _, wantTTL := range []uint8{1, 2, 50, 64, 128, 254, 255} { t.Run(fmt.Sprintf("TTL:%d", wantTTL), func(t *testing.T) { @@ -1658,8 +1652,9 @@ func TestSetTTL(t *testing.T) { c.createEndpointForFlow(flow) - if err := c.ep.SetSockOptInt(tcpip.TTLOption, int(wantTTL)); err != nil { - c.t.Fatalf("SetSockOptInt(TTLOption, %d) failed: %s", wantTTL, err) + opt := flow.ttlOption() + if err := c.ep.SetSockOptInt(opt, int(wantTTL)); err != nil { + c.t.Fatalf("SetSockOptInt(%d, %d) failed: %s", opt, wantTTL, err) } testWrite(c, flow, checker.TTL(wantTTL))