{"record":{"id":"2f3ef103191795de","repo":"netbirdio/netbird","slug":"set-network-layer-for-udp-checksum-w","errorCode":null,"errorMessage":"set network layer for UDP checksum: %w","messagePattern":"set network layer for UDP checksum: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/uspfilter/tracer.go","lineNumber":200,"sourceCode":"\t\tPSH:     p.TCPState != nil && p.TCPState.PSH,\n\t\tURG:     p.TCPState != nil && p.TCPState.URG,\n\t}\n\tif nl, ok := ipLayer.(gopacket.NetworkLayer); ok {\n\t\tif err := tcp.SetNetworkLayerForChecksum(nl); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"set network layer for TCP checksum: %w\", err)\n\t\t}\n\t}\n\treturn []gopacket.SerializableLayer{tcp}, nil\n}\n\nfunc (p *PacketBuilder) buildUDPLayer(ipLayer gopacket.SerializableLayer) ([]gopacket.SerializableLayer, error) {\n\tudp := &layers.UDP{\n\t\tSrcPort: layers.UDPPort(p.SrcPort),\n\t\tDstPort: layers.UDPPort(p.DstPort),\n\t}\n\tif nl, ok := ipLayer.(gopacket.NetworkLayer); ok {\n\t\tif err := udp.SetNetworkLayerForChecksum(nl); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"set network layer for UDP checksum: %w\", err)\n\t\t}\n\t}\n\treturn []gopacket.SerializableLayer{udp}, nil\n}\n\nfunc (p *PacketBuilder) buildICMPLayer(ipLayer gopacket.SerializableLayer) ([]gopacket.SerializableLayer, error) {\n\tif p.SrcIP.Is6() || p.DstIP.Is6() {\n\t\ticmp := &layers.ICMPv6{\n\t\t\tTypeCode: layers.CreateICMPv6TypeCode(p.ICMPType, p.ICMPCode),\n\t\t}\n\t\tif nl, ok := ipLayer.(gopacket.NetworkLayer); ok {\n\t\t\t_ = icmp.SetNetworkLayerForChecksum(nl)\n\t\t}\n\t\tif p.ICMPType == layers.ICMPv6TypeEchoRequest || p.ICMPType == layers.ICMPv6TypeEchoReply {\n\t\t\techo := &layers.ICMPv6Echo{\n\t\t\t\tIdentifier: 1,\n\t\t\t\tSeqNumber:  1,\n\t\t\t}","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/uspfilter/tracer.go#L182-L218","documentation":"Same gopacket constraint as the TCP variant: UDP's SetNetworkLayerForChecksum errors when the network layer address size does not match the address family needed for the UDP pseudo-header (4 bytes for IPv4, 16 for IPv6). The tracer sets it so SerializeOptions{ComputeChecksums:true} produces a valid UDP checksum, which matters because many stacks silently drop UDP with a zero/computed-wrong checksum over IPv6.","triggerScenarios":"Handing the UDP builder an ipLayer whose family differs from the address data used for the ports/addresses, or invoking buildUDPLayer directly with a mismatched layer; realistically only after modifying the layer assembly order in the tracer.","commonSituations":"Custom diagnostics built on PacketBuilder that assemble layers manually; gopacket dependency upgrades altering NetworkLayer address handling.","solutions":["Always call buildUDPLayer with the exact ipLayer produced by buildIPLayer in the same Build invocation","Validate SrcIP/DstIP family equality up front (the buildIPLayer guard) so mismatched input never reaches layer assembly","Write a trace test covering UDP over both IPv4 and IPv6 to lock the behavior","Check the gopacket error detail to see which side (4 vs 16 bytes) is inconsistent"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if b.SrcIP.Is4() != b.DstIP.Is4() || !b.SrcIP.IsValid() {\n    return errors.New(\"addresses must be valid and same-family\")\n}","typeGuard":"func (p *PacketBuilder) udpBuildable() bool {\n    return p.SrcIP.IsValid() && p.DstIP.IsValid() && p.SrcIP.Is4() == p.DstIP.Is4() &&\n        (p.Protocol == fw.ProtocolUDP || p.Protocol == fw.ProtocolTCP || p.Protocol == fw.ProtocolICMP)\n}","tryCatchPattern":"if _, err := b.Build(); err != nil {\n    var se interface{ Error() string }\n    _ = se\n    if strings.Contains(err.Error(), \"UDP checksum\") {\n        return fmt.Errorf(\"rebuild packet with matched families: %w\", err)\n    }\n    return err\n}","preventionTips":["Always pair the UDP layer with the ipLayer from the same Build invocation","Cover UDP over IPv6 in tests: a wrong pseudo-header is silent until a peer drops the packet","Normalize all addresses with Unmap() before entering the builder"],"tags":["go","netbird","gopacket","udp","checksum","tracer"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}