{"record":{"id":"141590f1148888d0","repo":"OpenNHP/opennhp","slug":"packet-total-size-is-incorrect","errorCode":null,"errorMessage":"packet total size is incorrect","messagePattern":"packet total size is incorrect","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"nhp/core/packet.go","lineNumber":258,"sourceCode":"func (d *Device) RecvPrecheck(pkt *Packet) (int, int, error) {\n\theaderSize := pkt.Header().Size()\n\n\t// check type and payload size\n\tt, s := pkt.HeaderTypeAndSize()\n\tif t == NHP_KPL {\n\t\tif s == 0 {\n\t\t\treturn t, s, nil\n\t\t} else {\n\t\t\treturn t, s, fmt.Errorf(\"keepalive packet size is incorrect\")\n\t\t}\n\t}\n\tif !d.CheckRecvHeaderType(t) {\n\t\treturn t, s, fmt.Errorf(\"packet header type does not match device\")\n\t}\n\n\ttotalLen := len(pkt.Content)\n\tif totalLen != headerSize+s {\n\t\treturn t, s, fmt.Errorf(\"packet total size is incorrect\")\n\t}\n\n\treturn t, s, nil\n}\n\nfunc (d *Device) AllocatePoolPacket() *Packet {\n\tbuf := d.pool.Get()\n\treturn &Packet{Buf: buf, Content: buf[:], PoolAllocated: true}\n}\n\nfunc (d *Device) ReleasePoolPacket(pkt *Packet) {\n\tif pkt != nil && pkt.Buf != nil && pkt.PoolAllocated {\n\t\td.pool.Put(pkt.Buf)\n\t\tpkt.Buf = nil\n\t\tpkt.Content = nil\n\t}\n}\n","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/core/packet.go#L240-L276","documentation":"Device.RecvPrecheck compares the buffer's total length with headerSize plus the payload size declared in the packet header. A mismatch means the datagram is truncated, padded, or otherwise malformed, so parsing would read out of bounds; the packet is rejected before decryption.","triggerScenarios":"recvPacketRoutine, HandleRelayForward, or PacketToMsg reads a datagram where len(pkt.Content) != headerSize + s (declared header payload size), e.g. UDP truncation or a corrupted size field.","commonSituations":"Using a receive buffer smaller than the datagram so UDP truncates it; fragmentation issues on constrained networks; hand-crafted or fuzzed packets; relay forwarding with modified buffers.","solutions":["Size the UDP receive buffer to the maximum NHP packet size so nothing is truncated","Check that relays forward the datagram unmodified (same length)","Log header size vs actual length to identify systematic truncation","If sender-side, ensure SetHeaderTypeAndSize is called after the full payload is written"],"exampleFix":"// before\nbuf := make([]byte, 256) // too small for full packet\nn, _ := conn.Read(buf)\n// after\nbuf := make([]byte, nhpcore.MaxPacketSize)\nn, _ := conn.Read(buf)\npkt := &nhpcore.Packet{Content: buf[:n]}","handlingStrategy":"validation","validationCode":"if len(pkt.Content) < nhpcore.HeaderSize {\n    return errors.New(\"truncated packet\")\n}\nt, s := pkt.HeaderTypeAndSize()\nif len(pkt.Content) != nhpcore.HeaderSize+s {\n    return errors.New(\"length mismatch\")\n}","typeGuard":"func fullPacket(pkt *nhpcore.Packet) bool {\n    t, s := pkt.HeaderTypeAndSize()\n    return len(pkt.Content) == nhpcore.HeaderSize+s && t >= 0\n}","tryCatchPattern":"if _, _, err := dev.RecvPrecheck(pkt); err != nil && strings.Contains(err.Error(), \"total size is incorrect\") {\n    log.Warnf(\"malformed datagram (%d bytes) dropped\", len(pkt.Content))\n    return\n}","preventionTips":["Allocate receive buffers large enough for max-size NHP packets","Ensure relays forward datagrams byte-for-byte","Check MTU/fragmentation on lossy links"],"tags":["go","udp","packet-size"],"backgroundTag":"schema-validation-failed","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}