{"record":{"id":"eb31dd27dc5950cd","repo":"slackhq/nebula","slug":"udp-header-len-mismatch-d","errorCode":null,"errorMessage":"udp header len mismatch: %d","messagePattern":"udp header len mismatch: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/tio/virtio/segment_linux.go","lineNumber":336,"sourceCode":"// into pkt at offset i*GSOSize and yielding pkt[i*GSOSize:i*GSOSize+segLen] to the caller.\n// Per-segment patches are total_len + IPv4 csum (or IPv6 payload_len) plus the UDP length and checksum.\n// pkt is consumed destructively.\nfunc SegmentUDP(pkt []byte, hdrLenU, csumStartU, gsoSizeU uint16, yield func(seg []byte) error) error {\n\tif gsoSizeU == 0 {\n\t\treturn fmt.Errorf(\"gso_size is zero\")\n\t}\n\tif csumStartU == 0 {\n\t\treturn fmt.Errorf(\"csum_start is zero\")\n\t}\n\n\tisV4 := pkt[0]>>4 == 4\n\theaderLen := int(hdrLenU)\n\tcsumStart := int(csumStartU)\n\tif headerLen > maxSegHdrLen {\n\t\treturn fmt.Errorf(\"header len %d exceeds max %d\", headerLen, maxSegHdrLen)\n\t}\n\tif headerLen-csumStart != udpHeaderLen {\n\t\treturn fmt.Errorf(\"udp header len mismatch: %d\", headerLen-csumStart)\n\t}\n\n\tpayLen := len(pkt) - headerLen\n\tgsoSize := int(gsoSizeU)\n\tnumSeg := segCount(payLen, gsoSize)\n\n\tbaseProtoSum := basePseudoSum(pkt, isV4, unix.IPPROTO_UDP)\n\n\tvar origIPID uint16\n\tvar baseIPHdrSum uint32\n\tif isV4 {\n\t\torigIPID = binary.BigEndian.Uint16(pkt[ipv4IDOff : ipv4IDOff+2])\n\t\tvar err error\n\t\t// Software UDP GSO bumps the ID per segment just like TSO\n\t\t// (inet_gso_segment's fixed-ID case is TCP-only), so it stays out of the base sum.\n\t\tbaseIPHdrSum, err = baseIPv4HdrSum(pkt, csumStart)\n\t\tif err != nil {\n\t\t\treturn err","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/tio/virtio/segment_linux.go#L318-L354","documentation":"Packet-validation error in SegmentUDP (virtio GSO segmentation): the UDP header length field found in the packet does not equal the expected 8 bytes for some segment. The computed per-segment UDP length disagrees with the on-wire header, indicating a corrupted or non-GSO packet passed to the segmentation path.","triggerScenarios":"Thrown at overlay/tio/virtio/segment_linux.go:336 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Drop the packet and rely on retransmission","Verify the GSO metadata (hdrLen, csumStart, gsoSize) matches the actual packet layout","Disable GSO offload for the tun device if the kernel/peer negotiation is unreliable"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}