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))