{"record":{"id":"6f091d04da02ce8d","repo":"nats-io/nats-server","slug":"invalid-dest-port-w","errorCode":null,"errorMessage":"invalid dest port: %w","messagePattern":"invalid dest port: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/client_proxyproto.go","lineNumber":205,"sourceCode":"\t}\n\n\tprotocol := parts[0]\n\tsrcIP := net.ParseIP(parts[1])\n\tdstIP := net.ParseIP(parts[2])\n\n\tif srcIP == nil || dstIP == nil {\n\t\treturn nil, nil, fmt.Errorf(\"%w: invalid address\", errProxyProtoInvalid)\n\t}\n\n\t// Parse ports\n\tsrcPort, err := strconv.ParseUint(parts[3], 10, 16)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"invalid source port: %w\", err)\n\t}\n\n\tdstPort, err := strconv.ParseUint(parts[4], 10, 16)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"invalid dest port: %w\", err)\n\t}\n\n\t// Validate protocol matches IP version. The textual form determines the\n\t// family: TCP4 requires dotted-quad addresses, TCP6 requires IPv6\n\t// addresses. IPv4-mapped IPv6 addresses (e.g. \"::ffff:192.0.2.1\") are\n\t// valid for TCP6 since dual-stack proxies can emit those for IPv4\n\t// clients on IPv6 sockets, matching the v2 parser behavior.\n\tsrcIsV6 := strings.Contains(parts[1], \":\")\n\tdstIsV6 := strings.Contains(parts[2], \":\")\n\tif protocol == proxyProtoV1TCP4 && (srcIsV6 || dstIsV6) {\n\t\treturn nil, nil, fmt.Errorf(\"%w: TCP4 with IPv6 address\", errProxyProtoInvalid)\n\t}\n\tif protocol == proxyProtoV1TCP6 && (!srcIsV6 || !dstIsV6) {\n\t\treturn nil, nil, fmt.Errorf(\"%w: TCP6 with IPv4 address\", errProxyProtoInvalid)\n\t}\n\tif protocol != proxyProtoV1TCP4 && protocol != proxyProtoV1TCP6 {\n\t\treturn nil, nil, fmt.Errorf(\"%w: invalid protocol %s\", errProxyProtoInvalid, protocol)\n\t}","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/client_proxyproto.go#L187-L223","documentation":"The v1 header's destination-port field could not be parsed by strconv.ParseUint base 10 with bit size 16. The field was empty, non-numeric, negative, or above 65535. The server wraps the strconv error and aborts the connection.","triggerScenarios":"Header contains a bad destination port such as 'PROXY TCP4 192.0.2.1 198.51.100.7 35646 https\\r\\n' or '65536'.","commonSituations":"Proxy configured to emit a service name instead of a numeric port; template variable left unfilled; corruption from a misbehaving intermediary rewriting the header.","solutions":["Ensure the destination-port field is a decimal number in 0-65535","Fix the proxy configuration to use the numeric listen port (e.g. 4222) not a service name","Inspect the raw header with tcpdump to see the offending field","Correct test fixtures to use numeric ports"],"exampleFix":"// before\n\"PROXY TCP4 192.0.2.1 198.51.100.7 35646 https\\r\\n\"\n// after\n\"PROXY TCP4 192.0.2.1 198.51.100.7 35646 4222\\r\\n\"","handlingStrategy":"validation","validationCode":"dport, err := strconv.ParseUint(dstPortStr, 10, 16)\nif err != nil {\n    return fmt.Errorf(\"refusing to send PROXY header: bad dest port %q\", dstPortStr)\n}","typeGuard":"func validPort(s string) bool {\n    p, err := strconv.ParseUint(s, 10, 16)\n    return err == nil && p > 0\n}","tryCatchPattern":"_, _, err := readProxyProtoHeader(conn)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid dest port\") {\n        log.Printf(\"peer sent bad PROXY dst port: %v\", err)\n        return\n    }\n    return err\n}","preventionTips":["Use the numeric listen port (e.g. 4222), not a service name like 'nats'","Ensure template variables for the destination port are always populated","Range-check ports to 1-65535 before sending"],"tags":["proxy-protocol","network","port","nats"],"backgroundTag":"proxy-protocol-invalid-header","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}