udp_mtu_v6_test.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package amneziawgnet
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "net/netip"
  6. "strings"
  7. "testing"
  8. "time"
  9. "gvisor.dev/gvisor/pkg/tcpip"
  10. "gvisor.dev/gvisor/pkg/tcpip/checksum"
  11. "gvisor.dev/gvisor/pkg/tcpip/header"
  12. )
  13. func TestWriteUDPReplyIPv6MTU(t *testing.T) {
  14. for _, tc := range []struct {
  15. name string
  16. size int
  17. fragmented bool
  18. }{
  19. {"small", 80, false}, {"boundary", 1232, false}, {"fragmented", 1452, true},
  20. } {
  21. t.Run(tc.name, func(t *testing.T) {
  22. tun, gstack, err := createNetTUNWithStack([]netip.Addr{netip.MustParseAddr("fd00::1")}, 1280)
  23. if err != nil {
  24. t.Fatal(err)
  25. }
  26. defer tun.Close()
  27. enablePromiscuousRouting(gstack)
  28. from := netip.MustParseAddrPort("[2001:db8::abcd]:5353")
  29. to := netip.MustParseAddrPort("[fd00::2]:49152")
  30. payload := make([]byte, tc.size)
  31. for i := range payload {
  32. payload[i] = byte(i*51 + 7)
  33. }
  34. if err := WriteUDPReply(gstack, from, to, payload); err != nil {
  35. t.Fatal(err)
  36. }
  37. var data []byte
  38. var id uint32
  39. count := 0
  40. for {
  41. select {
  42. case v := <-tun.(*stackTun).incomingPacket:
  43. packet := append([]byte(nil), v.AsSlice()...)
  44. v.Release()
  45. if len(packet) > 1280 {
  46. t.Fatalf("IPv6 TUN packet length %d exceeds MTU", len(packet))
  47. }
  48. ip := header.IPv6(packet)
  49. if ip.SourceAddress().String() != from.Addr().String() || ip.DestinationAddress().String() != to.Addr().String() || int(ip.PayloadLength())+40 != len(packet) {
  50. t.Fatalf("IPv6 addresses/length invalid: %s -> %s, %d", ip.SourceAddress(), ip.DestinationAddress(), ip.PayloadLength())
  51. }
  52. var offset int
  53. more := false
  54. part := packet[40:]
  55. if tc.fragmented {
  56. if ip.TransportProtocol() != header.IPv6FragmentHeader {
  57. t.Fatalf("IPv6 NextHeader %d, want fragment", ip.TransportProtocol())
  58. }
  59. frag := header.IPv6Fragment(part)
  60. if frag.NextHeader() != uint8(header.UDPProtocolNumber) {
  61. t.Fatalf("fragment next header %d", frag.NextHeader())
  62. }
  63. offset = int(frag.FragmentOffset()) * 8
  64. more = frag.More()
  65. if count == 0 {
  66. id = frag.ID()
  67. } else if frag.ID() != id {
  68. t.Fatalf("fragment ID %d != %d", frag.ID(), id)
  69. }
  70. part = part[8:]
  71. } else if ip.TransportProtocol() != header.UDPProtocolNumber {
  72. t.Fatalf("IPv6 NextHeader %d", ip.TransportProtocol())
  73. }
  74. if offset != len(data) {
  75. t.Fatalf("fragment offset %d, want %d", offset, len(data))
  76. }
  77. data = append(data, part...)
  78. count++
  79. if !more {
  80. goto assembled
  81. }
  82. case <-time.After(time.Second):
  83. t.Fatal("IPv6 reply timed out")
  84. }
  85. }
  86. assembled:
  87. if tc.fragmented && count < 2 {
  88. t.Fatal("no IPv6 fragments")
  89. }
  90. if len(data) != len(payload)+8 || binary.BigEndian.Uint16(data[:2]) != from.Port() || binary.BigEndian.Uint16(data[2:4]) != to.Port() || binary.BigEndian.Uint16(data[4:6]) != uint16(len(data)) || !bytes.Equal(data[8:], payload) {
  91. t.Fatal("reassembled IPv6 UDP bytes/ports/length differ")
  92. }
  93. if checksum.Checksum(data, header.PseudoHeaderChecksum(header.UDPProtocolNumber, tcpip.AddrFromSlice(from.Addr().AsSlice()), tcpip.AddrFromSlice(to.Addr().AsSlice()), uint16(len(data)))) != 0xffff {
  94. t.Fatal("IPv6 UDP checksum invalid")
  95. }
  96. })
  97. }
  98. }
  99. func TestWriteUDPReplyRejectsInvalidDatagrams(t *testing.T) {
  100. tun, gstack, err := createNetTUNWithStack([]netip.Addr{netip.MustParseAddr("10.77.0.1"), netip.MustParseAddr("fd00::1")}, 1280)
  101. if err != nil {
  102. t.Fatal(err)
  103. }
  104. defer tun.Close()
  105. enablePromiscuousRouting(gstack)
  106. for _, tc := range []struct {
  107. name, from, to string
  108. size int
  109. want string
  110. }{
  111. {"mixed", "203.0.113.9:53", "[fd00::2]:4000", 1, "invalid UDP reply addresses"},
  112. {"zone", "[fe80::1%eth0]:53", "[fd00::2]:4000", 1, "invalid UDP reply addresses"},
  113. {"v4 length", "203.0.113.9:53", "10.77.0.2:4000", 65508, "IPv4 reply too large"},
  114. {"v6 length", "[2001:db8::1]:53", "[fd00::2]:4000", 65528, "UDP reply too large"},
  115. } {
  116. t.Run(tc.name, func(t *testing.T) {
  117. err := WriteUDPReply(gstack, netip.MustParseAddrPort(tc.from), netip.MustParseAddrPort(tc.to), make([]byte, tc.size))
  118. if err == nil || !strings.Contains(err.Error(), tc.want) {
  119. t.Fatalf("error = %v, want %q", err, tc.want)
  120. }
  121. select {
  122. case v := <-tun.(*stackTun).incomingPacket:
  123. v.Release()
  124. t.Fatal("invalid reply emitted packet")
  125. default:
  126. }
  127. })
  128. }
  129. }
  130. func TestWriteUDPReplyIPv6ZeroChecksumIsEncodedAsOnes(t *testing.T) {
  131. tun, gstack, err := createNetTUNWithStack([]netip.Addr{netip.MustParseAddr("fd00::1")}, 1280)
  132. if err != nil {
  133. t.Fatal(err)
  134. }
  135. defer tun.Close()
  136. enablePromiscuousRouting(gstack)
  137. from := netip.MustParseAddrPort("[2001:db8::abcd]:5353")
  138. to := netip.MustParseAddrPort("[fd00::2]:49152")
  139. src := tcpip.AddrFromSlice(from.Addr().AsSlice())
  140. dst := tcpip.AddrFromSlice(to.Addr().AsSlice())
  141. udp := make([]byte, 10)
  142. binary.BigEndian.PutUint16(udp[0:2], from.Port())
  143. binary.BigEndian.PutUint16(udp[2:4], to.Port())
  144. binary.BigEndian.PutUint16(udp[4:6], uint16(len(udp)))
  145. pseudo := header.PseudoHeaderChecksum(header.UDPProtocolNumber, src, dst, uint16(len(udp)))
  146. var found bool
  147. for n := 0; n <= 65535; n++ {
  148. binary.BigEndian.PutUint16(udp[8:], uint16(n))
  149. if checksum.Checksum(udp, pseudo) == 0xffff {
  150. found = true
  151. break
  152. }
  153. }
  154. if !found {
  155. t.Fatal("no zero-complement checksum payload found")
  156. }
  157. if err := WriteUDPReply(gstack, from, to, udp[8:]); err != nil {
  158. t.Fatal(err)
  159. }
  160. select {
  161. case v := <-tun.(*stackTun).incomingPacket:
  162. packet := append([]byte(nil), v.AsSlice()...)
  163. v.Release()
  164. if got := binary.BigEndian.Uint16(packet[46:48]); got != 0xffff {
  165. t.Fatalf("IPv6 UDP checksum = %#04x, want 0xffff (zero is invalid)", got)
  166. }
  167. case <-time.After(time.Second):
  168. t.Fatal("reply timed out")
  169. }
  170. }