{"record":{"id":"c65113a4973dc1ee","repo":"XTLS/Xray-core","slug":"unexpected-client-ip-length","errorCode":null,"errorMessage":"unexpected client IP length ","messagePattern":"unexpected client IP length ","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/dns/dns.go","lineNumber":49,"sourceCode":"\tdomainMatcher          geodata.DomainMatcher\n\tmatcherInfos           []*DomainMatcherInfo\n\tcheckSystem            bool\n}\n\n// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher.\ntype DomainMatcherInfo struct {\n\tclientIdx  uint16\n\tdomainRule string\n}\n\n// New creates a new DNS server with given configuration.\nfunc New(ctx context.Context, config *Config) (*DNS, error) {\n\tvar clientIP net.IP\n\tswitch len(config.ClientIp) {\n\tcase 0, net.IPv4len, net.IPv6len:\n\t\tclientIP = net.IP(config.ClientIp)\n\tdefault:\n\t\treturn nil, errors.New(\"unexpected client IP length \", len(config.ClientIp))\n\t}\n\n\tvar ipOption dns.IPOption\n\tcheckSystem := false\n\tswitch config.QueryStrategy {\n\tcase QueryStrategy_USE_IP:\n\t\tipOption = dns.IPOption{\n\t\t\tIPv4Enable: true,\n\t\t\tIPv6Enable: true,\n\t\t\tFakeEnable: false,\n\t\t}\n\tcase QueryStrategy_USE_SYS:\n\t\tipOption = dns.IPOption{\n\t\t\tIPv4Enable: true,\n\t\t\tIPv6Enable: true,\n\t\t\tFakeEnable: false,\n\t\t}\n\t\tcheckSystem = true","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/app/dns/dns.go#L31-L67","documentation":"A padding schedule is an alternating dialogue: each turn must switch direction (client-to-server, then server-to-client, and so on). validatePaddingSchedule rejects two consecutive turns with the same direction, because both sides would simultaneously wait to read (deadlock) or both write (protocol desync).","triggerScenarios":"schedule[i].direction == schedule[i-1].direction for any i > 0. Caught by validatePaddingSchedule at startup, before traffic.","commonSituations":"Inserting an extra client-to-server turn to add cover traffic without flipping the next turn's direction; generating schedules programmatically with a direction bug; hand-editing a copied schedule and dropping the alternation.","solutions":["Flip the direction of turn i (or i-1) so consecutive turns alternate","If both directions are genuinely needed back-to-back, merge the intent into one turn or insert a turn of the opposite direction between them","Add a unit assertion over generated schedules that directions strictly alternate"],"exampleFix":"// before\n[]paddingTurn{\n  {direction: paddingClientToServer, minLength: 100, maxLength: 200},\n  {direction: paddingClientToServer, minLength: 100, maxLength: 200},\n}\n// after\n[]paddingTurn{\n  {direction: paddingClientToServer, minLength: 100, maxLength: 200},\n  {direction: paddingServerToClient, minLength: 100, maxLength: 200},\n}","handlingStrategy":"validation","validationCode":"func directionsAlternate(s []paddingTurn) bool {\n    for i := 1; i < len(s); i++ {\n        if s[i].direction == s[i-1].direction {\n            return false\n        }\n    }\n    return true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate schedules from a direction parameter that flips each iteration","Unit-test alternation over every fixture schedule"],"tags":["padding","config","validation","schedule","xmc"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}