{"record":{"id":"4d8235152603f4e9","repo":"slackhq/nebula","slug":"erripv6packettooshort","errorCode":"ErrIPv6PacketTooShort","errorMessage":"ipv6 packet is too short","messagePattern":"ipv6 packet is too short","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"outside.go","lineNumber":315,"sourceCode":"\t\t}\n\n\t\thostinfo.logger(f.l).Info(\"Host roamed to new udp ip/port.\",\n\t\t\t\"udpAddr\", curRemote,\n\t\t\t\"newAddr\", via.UdpAddr,\n\t\t)\n\t\thostinfo.lastRoam = time.Now()\n\t\thostinfo.lastRoamRemote = curRemote\n\t\thostinfo.SetRemote(via.UdpAddr)\n\t}\n\n}\n\nvar (\n\tErrPacketTooShort          = errors.New(\"packet is too short\")\n\tErrUnknownIPVersion        = errors.New(\"packet is an unknown ip version\")\n\tErrIPv4InvalidHeaderLength = errors.New(\"invalid ipv4 header length\")\n\tErrIPv4PacketTooShort      = errors.New(\"ipv4 packet is too short\")\n\tErrIPv6PacketTooShort      = errors.New(\"ipv6 packet is too short\")\n)\n\n// newPacket validates and parses the interesting bits for the firewall out of the ip and sub protocol headers\nfunc newPacket(data []byte, incoming bool, fp *firewall.ParsedPacket) error {\n\t// fp is reused across packets; reset the parse byproducts so an early-error return cannot\n\t// leak the previous packet's offsets.\n\tfp.IPHdrLen = 0\n\tfp.FragAny = false\n\tif len(data) < 1 {\n\t\treturn ErrPacketTooShort\n\t}\n\n\tversion := int((data[0] >> 4) & 0x0f)\n\tswitch version {\n\tcase ipv4.Version:\n\t\treturn parseV4(data, incoming, fp)\n\tcase ipv6.Version:\n\t\treturn parseV6(data, incoming, fp)","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/outside.go#L297-L333","documentation":"ErrIPv6PacketTooShort is returned by newPacket (via parseV6) when an inbound packet cannot be parsed as IPv6 because the buffer is shorter than the fixed IPv6 header (ipv6.HeaderLen, 40 bytes) or because iputil.IPv6FindUpperProtocol cannot walk the extension headers to find an upper-layer protocol. It guards the firewall parser from indexing out of bounds on truncated or malformed packets.","triggerScenarios":"parseV6 receives data with len(data) < ipv6.HeaderLen (outside.go:341), or IPv6FindUpperProtocol fails to locate an upper protocol / walk extension headers within the buffer (outside.go:357). Directly triggered by any call path that feeds a truncated, corrupted, or deliberately malformed IPv6 datagram into newPacket.","commonSituations":"MTU mismatches or offloads (TSO/GSO/LRO) delivering partial frames, buggy NIC or tunnel software truncating packets, hostile peers sending malformed packets to probe the firewall, userspace readers that slice a packet buffer too short before calling the parser.","solutions":["Log the peer and actual len(data) to identify the truncating source (NIC offload, tunnel, or peer).","Verify MTU settings end-to-end (host NIC, VPN/tunnel overhead, VPN preferred MTU) and reduce MTU if fragmentation/overflow is suspected.","Disable or update GRO/GSO/LRO offload on the receiving interface if truncation correlates with offloaded traffic.","Ensure the caller passes the full received buffer to newPacket instead of a truncated slice.","If malicious input is the cause, treat as expected: the error is a safe rejection and the packet should be dropped."],"exampleFix":"// before: blindly parse whatever was read\nn, _ := conn.Read(buf)\nerr := newPacket(buf[:n], incoming, fp)\n// after: pre-validate minimum IPv6 header length\nn, _ := conn.Read(buf)\nif n >= ipv6.HeaderLen && buf[0]>>4 == 6 {\n    err = newPacket(buf[:n], incoming, fp)\n} else {\n    // drop / count as malformed\n}","handlingStrategy":"validation","validationCode":"func isParseableIPv6(pkt []byte) bool {\n    return len(pkt) >= ipv6.HeaderLen && pkt[0]>>4 == 6\n}\nif !isParseableIPv6(buf[:n]) {\n    stats.MalformedV6++\n    return nil // drop before calling newPacket\n}","typeGuard":"func ipv6HeaderPresent(b []byte) bool {\n    if len(b) < ipv6.HeaderLen {\n        return false\n    }\n    return b[0]>>4 == 6\n}","tryCatchPattern":"if err := newPacket(data, incoming, fp); err != nil {\n    if errors.Is(err, ErrIPv6PacketTooShort) {\n        log.Debug(\"dropping short ipv6 packet\", \"len\", len(data), \"src\", src)\n        return nil // safe rejection\n    }\n    return err\n}","preventionTips":["Validate minimum header length and IP version before handing buffers to the parser.","Audit MTU and offload (GRO/GSO/LRO) settings on receiving interfaces.","Never slice packet buffers by assumed header sizes; use the actual read length.","Count short-packet rejections per peer to detect hostile or buggy senders early."],"tags":["network","ipv6","packet-parsing","firewall"],"backgroundTag":"packet-too-short","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}