github.com/polevpn/netstack@v1.10.9/tcpip/network/ipv4/ipv4_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ipv4_test 16 17 import ( 18 "bytes" 19 "encoding/hex" 20 "math/rand" 21 "testing" 22 23 "github.com/polevpn/netstack/tcpip" 24 "github.com/polevpn/netstack/tcpip/buffer" 25 "github.com/polevpn/netstack/tcpip/header" 26 "github.com/polevpn/netstack/tcpip/link/channel" 27 "github.com/polevpn/netstack/tcpip/link/sniffer" 28 "github.com/polevpn/netstack/tcpip/network/ipv4" 29 "github.com/polevpn/netstack/tcpip/stack" 30 "github.com/polevpn/netstack/tcpip/transport/tcp" 31 "github.com/polevpn/netstack/tcpip/transport/udp" 32 "github.com/polevpn/netstack/waiter" 33 ) 34 35 func TestExcludeBroadcast(t *testing.T) { 36 s := stack.New(stack.Options{ 37 NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol()}, 38 TransportProtocols: []stack.TransportProtocol{udp.NewProtocol()}, 39 }) 40 41 const defaultMTU = 65536 42 ep := stack.LinkEndpoint(channel.New(256, defaultMTU, "")) 43 if testing.Verbose() { 44 ep = sniffer.New(ep) 45 } 46 if err := s.CreateNIC(1, ep); err != nil { 47 t.Fatalf("CreateNIC failed: %v", err) 48 } 49 50 s.SetRouteTable([]tcpip.Route{{ 51 Destination: header.IPv4EmptySubnet, 52 NIC: 1, 53 }}) 54 55 randomAddr := tcpip.FullAddress{NIC: 1, Addr: "\x0a\x00\x00\x01", Port: 53} 56 57 var wq waiter.Queue 58 t.Run("WithoutPrimaryAddress", func(t *testing.T) { 59 ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 60 if err != nil { 61 t.Fatal(err) 62 } 63 defer ep.Close() 64 65 // Cannot connect using a broadcast address as the source. 66 if err := ep.Connect(randomAddr); err != tcpip.ErrNoRoute { 67 t.Errorf("got ep.Connect(...) = %v, want = %v", err, tcpip.ErrNoRoute) 68 } 69 70 // However, we can bind to a broadcast address to listen. 71 if err := ep.Bind(tcpip.FullAddress{Addr: header.IPv4Broadcast, Port: 53, NIC: 1}); err != nil { 72 t.Errorf("Bind failed: %v", err) 73 } 74 }) 75 76 t.Run("WithPrimaryAddress", func(t *testing.T) { 77 ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 78 if err != nil { 79 t.Fatal(err) 80 } 81 defer ep.Close() 82 83 // Add a valid primary endpoint address, now we can connect. 84 if err := s.AddAddress(1, ipv4.ProtocolNumber, "\x0a\x00\x00\x02"); err != nil { 85 t.Fatalf("AddAddress failed: %v", err) 86 } 87 if err := ep.Connect(randomAddr); err != nil { 88 t.Errorf("Connect failed: %v", err) 89 } 90 }) 91 } 92 93 // makeHdrAndPayload generates a randomize packet. hdrLength indicates how much 94 // data should already be in the header before WritePacket. extraLength 95 // indicates how much extra space should be in the header. The payload is made 96 // from many Views of the sizes listed in viewSizes. 97 func makeHdrAndPayload(hdrLength int, extraLength int, viewSizes []int) (buffer.Prependable, buffer.VectorisedView) { 98 hdr := buffer.NewPrependable(hdrLength + extraLength) 99 hdr.Prepend(hdrLength) 100 rand.Read(hdr.View()) 101 102 var views []buffer.View 103 totalLength := 0 104 for _, s := range viewSizes { 105 newView := buffer.NewView(s) 106 rand.Read(newView) 107 views = append(views, newView) 108 totalLength += s 109 } 110 payload := buffer.NewVectorisedView(totalLength, views) 111 return hdr, payload 112 } 113 114 // comparePayloads compared the contents of all the packets against the contents 115 // of the source packet. 116 func compareFragments(t *testing.T, packets []tcpip.PacketBuffer, sourcePacketInfo tcpip.PacketBuffer, mtu uint32) { 117 t.Helper() 118 // Make a complete array of the sourcePacketInfo packet. 119 source := header.IPv4(packets[0].Header.View()[:header.IPv4MinimumSize]) 120 source = append(source, sourcePacketInfo.Header.View()...) 121 source = append(source, sourcePacketInfo.Data.ToView()...) 122 123 // Make a copy of the IP header, which will be modified in some fields to make 124 // an expected header. 125 sourceCopy := header.IPv4(append(buffer.View(nil), source[:source.HeaderLength()]...)) 126 sourceCopy.SetChecksum(0) 127 sourceCopy.SetFlagsFragmentOffset(0, 0) 128 sourceCopy.SetTotalLength(0) 129 var offset uint16 130 // Build up an array of the bytes sent. 131 var reassembledPayload []byte 132 for i, packet := range packets { 133 // Confirm that the packet is valid. 134 allBytes := packet.Header.View().ToVectorisedView() 135 allBytes.Append(packet.Data) 136 ip := header.IPv4(allBytes.ToView()) 137 if !ip.IsValid(len(ip)) { 138 t.Errorf("IP packet is invalid:\n%s", hex.Dump(ip)) 139 } 140 if got, want := ip.CalculateChecksum(), uint16(0xffff); got != want { 141 t.Errorf("ip.CalculateChecksum() got %#x, want %#x", got, want) 142 } 143 if got, want := len(ip), int(mtu); got > want { 144 t.Errorf("fragment is too large, got %d want %d", got, want) 145 } 146 if got, want := packet.Header.UsedLength(), sourcePacketInfo.Header.UsedLength()+header.IPv4MinimumSize; i == 0 && want < int(mtu) && got != want { 147 t.Errorf("first fragment hdr parts should have unmodified length if possible: got %d, want %d", got, want) 148 } 149 if got, want := packet.Header.AvailableLength(), sourcePacketInfo.Header.AvailableLength()-header.IPv4MinimumSize; got != want { 150 t.Errorf("fragment #%d should have the same available space for prepending as source: got %d, want %d", i, got, want) 151 } 152 if i < len(packets)-1 { 153 sourceCopy.SetFlagsFragmentOffset(sourceCopy.Flags()|header.IPv4FlagMoreFragments, offset) 154 } else { 155 sourceCopy.SetFlagsFragmentOffset(sourceCopy.Flags()&^header.IPv4FlagMoreFragments, offset) 156 } 157 reassembledPayload = append(reassembledPayload, ip.Payload()...) 158 offset += ip.TotalLength() - uint16(ip.HeaderLength()) 159 // Clear out the checksum and length from the ip because we can't compare 160 // it. 161 sourceCopy.SetTotalLength(uint16(len(ip))) 162 sourceCopy.SetChecksum(0) 163 sourceCopy.SetChecksum(^sourceCopy.CalculateChecksum()) 164 if !bytes.Equal(ip[:ip.HeaderLength()], sourceCopy[:sourceCopy.HeaderLength()]) { 165 t.Errorf("ip[:ip.HeaderLength()] got:\n%s\nwant:\n%s", hex.Dump(ip[:ip.HeaderLength()]), hex.Dump(sourceCopy[:sourceCopy.HeaderLength()])) 166 } 167 } 168 expected := source[source.HeaderLength():] 169 if !bytes.Equal(reassembledPayload, expected) { 170 t.Errorf("reassembledPayload got:\n%s\nwant:\n%s", hex.Dump(reassembledPayload), hex.Dump(expected)) 171 } 172 } 173 174 type errorChannel struct { 175 *channel.Endpoint 176 Ch chan tcpip.PacketBuffer 177 packetCollectorErrors []*tcpip.Error 178 } 179 180 // newErrorChannel creates a new errorChannel endpoint. Each call to WritePacket 181 // will return successive errors from packetCollectorErrors until the list is 182 // empty and then return nil each time. 183 func newErrorChannel(size int, mtu uint32, linkAddr tcpip.LinkAddress, packetCollectorErrors []*tcpip.Error) *errorChannel { 184 return &errorChannel{ 185 Endpoint: channel.New(size, mtu, linkAddr), 186 Ch: make(chan tcpip.PacketBuffer, size), 187 packetCollectorErrors: packetCollectorErrors, 188 } 189 } 190 191 // Drain removes all outbound packets from the channel and counts them. 192 func (e *errorChannel) Drain() int { 193 c := 0 194 for { 195 select { 196 case <-e.Ch: 197 c++ 198 default: 199 return c 200 } 201 } 202 } 203 204 // WritePacket stores outbound packets into the channel. 205 func (e *errorChannel) WritePacket(r *stack.Route, gso *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) *tcpip.Error { 206 select { 207 case e.Ch <- pkt: 208 default: 209 } 210 211 nextError := (*tcpip.Error)(nil) 212 if len(e.packetCollectorErrors) > 0 { 213 nextError = e.packetCollectorErrors[0] 214 e.packetCollectorErrors = e.packetCollectorErrors[1:] 215 } 216 return nextError 217 } 218 219 type context struct { 220 stack.Route 221 linkEP *errorChannel 222 } 223 224 func buildContext(t *testing.T, packetCollectorErrors []*tcpip.Error, mtu uint32) context { 225 // Make the packet and write it. 226 s := stack.New(stack.Options{ 227 NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol()}, 228 }) 229 ep := newErrorChannel(100 /* Enough for all tests. */, mtu, "", packetCollectorErrors) 230 s.CreateNIC(1, ep) 231 const ( 232 src = "\x10\x00\x00\x01" 233 dst = "\x10\x00\x00\x02" 234 ) 235 s.AddAddress(1, ipv4.ProtocolNumber, src) 236 { 237 subnet, err := tcpip.NewSubnet(dst, tcpip.AddressMask(header.IPv4Broadcast)) 238 if err != nil { 239 t.Fatal(err) 240 } 241 s.SetRouteTable([]tcpip.Route{{ 242 Destination: subnet, 243 NIC: 1, 244 }}) 245 } 246 r, err := s.FindRoute(0, src, dst, ipv4.ProtocolNumber, false /* multicastLoop */) 247 if err != nil { 248 t.Fatalf("s.FindRoute got %v, want %v", err, nil) 249 } 250 return context{ 251 Route: r, 252 linkEP: ep, 253 } 254 } 255 256 func TestFragmentation(t *testing.T) { 257 var manyPayloadViewsSizes [1000]int 258 for i := range manyPayloadViewsSizes { 259 manyPayloadViewsSizes[i] = 7 260 } 261 fragTests := []struct { 262 description string 263 mtu uint32 264 gso *stack.GSO 265 hdrLength int 266 extraLength int 267 payloadViewsSizes []int 268 expectedFrags int 269 }{ 270 {"NoFragmentation", 2000, &stack.GSO{}, 0, header.IPv4MinimumSize, []int{1000}, 1}, 271 {"NoFragmentationWithBigHeader", 2000, &stack.GSO{}, 16, header.IPv4MinimumSize, []int{1000}, 1}, 272 {"Fragmented", 800, &stack.GSO{}, 0, header.IPv4MinimumSize, []int{1000}, 2}, 273 {"FragmentedWithGsoNil", 800, nil, 0, header.IPv4MinimumSize, []int{1000}, 2}, 274 {"FragmentedWithManyViews", 300, &stack.GSO{}, 0, header.IPv4MinimumSize, manyPayloadViewsSizes[:], 25}, 275 {"FragmentedWithManyViewsAndPrependableBytes", 300, &stack.GSO{}, 0, header.IPv4MinimumSize + 55, manyPayloadViewsSizes[:], 25}, 276 {"FragmentedWithBigHeader", 800, &stack.GSO{}, 20, header.IPv4MinimumSize, []int{1000}, 2}, 277 {"FragmentedWithBigHeaderAndPrependableBytes", 800, &stack.GSO{}, 20, header.IPv4MinimumSize + 66, []int{1000}, 2}, 278 {"FragmentedWithMTUSmallerThanHeaderAndPrependableBytes", 300, &stack.GSO{}, 1000, header.IPv4MinimumSize + 77, []int{500}, 6}, 279 } 280 281 for _, ft := range fragTests { 282 t.Run(ft.description, func(t *testing.T) { 283 hdr, payload := makeHdrAndPayload(ft.hdrLength, ft.extraLength, ft.payloadViewsSizes) 284 source := tcpip.PacketBuffer{ 285 Header: hdr, 286 // Save the source payload because WritePacket will modify it. 287 Data: payload.Clone(nil), 288 } 289 c := buildContext(t, nil, ft.mtu) 290 err := c.Route.WritePacket(ft.gso, stack.NetworkHeaderParams{Protocol: tcp.ProtocolNumber, TTL: 42, TOS: stack.DefaultTOS}, tcpip.PacketBuffer{ 291 Header: hdr, 292 Data: payload, 293 }) 294 if err != nil { 295 t.Errorf("err got %v, want %v", err, nil) 296 } 297 298 var results []tcpip.PacketBuffer 299 L: 300 for { 301 select { 302 case pi := <-c.linkEP.Ch: 303 results = append(results, pi) 304 default: 305 break L 306 } 307 } 308 309 if got, want := len(results), ft.expectedFrags; got != want { 310 t.Errorf("len(result) got %d, want %d", got, want) 311 } 312 if got, want := len(results), int(c.Route.Stats().IP.PacketsSent.Value()); got != want { 313 t.Errorf("no errors yet len(result) got %d, want %d", got, want) 314 } 315 compareFragments(t, results, source, ft.mtu) 316 }) 317 } 318 } 319 320 // TestFragmentationErrors checks that errors are returned from write packet 321 // correctly. 322 func TestFragmentationErrors(t *testing.T) { 323 fragTests := []struct { 324 description string 325 mtu uint32 326 hdrLength int 327 payloadViewsSizes []int 328 packetCollectorErrors []*tcpip.Error 329 }{ 330 {"NoFrag", 2000, 0, []int{1000}, []*tcpip.Error{tcpip.ErrAborted}}, 331 {"ErrorOnFirstFrag", 500, 0, []int{1000}, []*tcpip.Error{tcpip.ErrAborted}}, 332 {"ErrorOnSecondFrag", 500, 0, []int{1000}, []*tcpip.Error{nil, tcpip.ErrAborted}}, 333 {"ErrorOnFirstFragMTUSmallerThanHdr", 500, 1000, []int{500}, []*tcpip.Error{tcpip.ErrAborted}}, 334 } 335 336 for _, ft := range fragTests { 337 t.Run(ft.description, func(t *testing.T) { 338 hdr, payload := makeHdrAndPayload(ft.hdrLength, header.IPv4MinimumSize, ft.payloadViewsSizes) 339 c := buildContext(t, ft.packetCollectorErrors, ft.mtu) 340 err := c.Route.WritePacket(&stack.GSO{}, stack.NetworkHeaderParams{Protocol: tcp.ProtocolNumber, TTL: 42, TOS: stack.DefaultTOS}, tcpip.PacketBuffer{ 341 Header: hdr, 342 Data: payload, 343 }) 344 for i := 0; i < len(ft.packetCollectorErrors)-1; i++ { 345 if got, want := ft.packetCollectorErrors[i], (*tcpip.Error)(nil); got != want { 346 t.Errorf("ft.packetCollectorErrors[%d] got %v, want %v", i, got, want) 347 } 348 } 349 // We only need to check that last error because all the ones before are 350 // nil. 351 if got, want := err, ft.packetCollectorErrors[len(ft.packetCollectorErrors)-1]; got != want { 352 t.Errorf("err got %v, want %v", got, want) 353 } 354 if got, want := c.linkEP.Drain(), int(c.Route.Stats().IP.PacketsSent.Value())+1; err != nil && got != want { 355 t.Errorf("after linkEP error len(result) got %d, want %d", got, want) 356 } 357 }) 358 } 359 } 360 361 func TestInvalidFragments(t *testing.T) { 362 // These packets have both IHL and TotalLength set to 0. 363 testCases := []struct { 364 name string 365 packets [][]byte 366 wantMalformedIPPackets uint64 367 wantMalformedFragments uint64 368 }{ 369 { 370 "ihl_totallen_zero_valid_frag_offset", 371 [][]byte{ 372 {0x40, 0x30, 0x00, 0x00, 0x6c, 0x74, 0x7d, 0x30, 0x30, 0x30, 0x30, 0x30, 0x39, 0x32, 0x39, 0x33, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 373 }, 374 1, 375 0, 376 }, 377 { 378 "ihl_totallen_zero_invalid_frag_offset", 379 [][]byte{ 380 {0x40, 0x30, 0x00, 0x00, 0x6c, 0x74, 0x20, 0x00, 0x30, 0x30, 0x30, 0x30, 0x39, 0x32, 0x39, 0x33, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 381 }, 382 1, 383 0, 384 }, 385 { 386 // Total Length of 37(20 bytes IP header + 17 bytes of 387 // payload) 388 // Frag Offset of 0x1ffe = 8190*8 = 65520 389 // Leading to the fragment end to be past 65535. 390 "ihl_totallen_valid_invalid_frag_offset_1", 391 [][]byte{ 392 {0x45, 0x30, 0x00, 0x25, 0x6c, 0x74, 0x1f, 0xfe, 0x30, 0x30, 0x30, 0x30, 0x39, 0x32, 0x39, 0x33, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 393 }, 394 1, 395 1, 396 }, 397 // The following 3 tests were found by running a fuzzer and were 398 // triggering a panic in the IPv4 reassembler code. 399 { 400 "ihl_less_than_ipv4_minimum_size_1", 401 [][]byte{ 402 {0x42, 0x30, 0x0, 0x30, 0x30, 0x40, 0x0, 0xf3, 0x30, 0x1, 0x30, 0x30, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 403 {0x42, 0x30, 0x0, 0x8, 0x30, 0x40, 0x20, 0x0, 0x30, 0x1, 0x30, 0x30, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 404 }, 405 2, 406 0, 407 }, 408 { 409 "ihl_less_than_ipv4_minimum_size_2", 410 [][]byte{ 411 {0x42, 0x30, 0x0, 0x30, 0x30, 0x40, 0xb3, 0x12, 0x30, 0x6, 0x30, 0x30, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 412 {0x42, 0x30, 0x0, 0x8, 0x30, 0x40, 0x20, 0x0, 0x30, 0x6, 0x30, 0x30, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 413 }, 414 2, 415 0, 416 }, 417 { 418 "ihl_less_than_ipv4_minimum_size_3", 419 [][]byte{ 420 {0x42, 0x30, 0x0, 0x30, 0x30, 0x40, 0xb3, 0x30, 0x30, 0x6, 0x30, 0x30, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 421 {0x42, 0x30, 0x0, 0x8, 0x30, 0x40, 0x20, 0x0, 0x30, 0x6, 0x30, 0x30, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 422 }, 423 2, 424 0, 425 }, 426 { 427 "fragment_with_short_total_len_extra_payload", 428 [][]byte{ 429 {0x46, 0x30, 0x00, 0x30, 0x30, 0x40, 0x0e, 0x12, 0x30, 0x06, 0x30, 0x30, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 430 {0x46, 0x30, 0x00, 0x18, 0x30, 0x40, 0x20, 0x00, 0x30, 0x06, 0x30, 0x30, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 431 }, 432 1, 433 1, 434 }, 435 { 436 "multiple_fragments_with_more_fragments_set_to_false", 437 [][]byte{ 438 {0x45, 0x00, 0x00, 0x1c, 0x30, 0x40, 0x00, 0x10, 0x00, 0x06, 0x34, 0x69, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 439 {0x45, 0x00, 0x00, 0x1c, 0x30, 0x40, 0x00, 0x01, 0x61, 0x06, 0x34, 0x69, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 440 {0x45, 0x00, 0x00, 0x1c, 0x30, 0x40, 0x20, 0x00, 0x00, 0x06, 0x34, 0x1e, 0x73, 0x73, 0x69, 0x6e, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 441 }, 442 1, 443 1, 444 }, 445 } 446 447 for _, tc := range testCases { 448 t.Run(tc.name, func(t *testing.T) { 449 const nicID tcpip.NICID = 42 450 s := stack.New(stack.Options{ 451 NetworkProtocols: []stack.NetworkProtocol{ 452 ipv4.NewProtocol(), 453 }, 454 }) 455 456 var linkAddr = tcpip.LinkAddress([]byte{0x30, 0x30, 0x30, 0x30, 0x30, 0x30}) 457 var remoteLinkAddr = tcpip.LinkAddress([]byte{0x30, 0x30, 0x30, 0x30, 0x30, 0x31}) 458 ep := channel.New(10, 1500, linkAddr) 459 s.CreateNIC(nicID, sniffer.New(ep)) 460 461 for _, pkt := range tc.packets { 462 ep.InjectLinkAddr(header.IPv4ProtocolNumber, remoteLinkAddr, tcpip.PacketBuffer{ 463 Data: buffer.NewVectorisedView(len(pkt), []buffer.View{pkt}), 464 }) 465 } 466 467 if got, want := s.Stats().IP.MalformedPacketsReceived.Value(), tc.wantMalformedIPPackets; got != want { 468 t.Errorf("incorrect Stats.IP.MalformedPacketsReceived, got: %d, want: %d", got, want) 469 } 470 if got, want := s.Stats().IP.MalformedFragmentsReceived.Value(), tc.wantMalformedFragments; got != want { 471 t.Errorf("incorrect Stats.IP.MalformedFragmentsReceived, got: %d, want: %d", got, want) 472 } 473 }) 474 } 475 }