{"record":{"id":"9f83105d755d30ea","repo":"ginuerzh/gost","slug":"bad-minor-version","errorCode":null,"errorMessage":"bad minor version","messagePattern":"bad minor version","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"obfs.go","lineNumber":322,"sourceCode":"\t\t0xc02c, 0xc030, 0x009f, 0xcca9, 0xcca8, 0xccaa, 0xc02b, 0xc02f,\n\t\t0x009e, 0xc024, 0xc028, 0x006b, 0xc023, 0xc027, 0x0067, 0xc00a,\n\t\t0xc014, 0x0039, 0xc009, 0xc013, 0x0033, 0x009d, 0x009c, 0x003d,\n\t\t0x003c, 0x0035, 0x002f, 0x00ff,\n\t}\n\n\tcompressionMethods = []uint8{0x00}\n\n\talgorithms = []uint16{\n\t\t0x0601, 0x0602, 0x0603, 0x0501, 0x0502, 0x0503, 0x0401, 0x0402,\n\t\t0x0403, 0x0301, 0x0302, 0x0303, 0x0201, 0x0202, 0x0203,\n\t}\n\n\ttlsRecordTypes   = []uint8{0x16, 0x14, 0x16, 0x17}\n\ttlsVersionMinors = []uint8{0x01, 0x03, 0x03, 0x03}\n\n\tErrBadType         = errors.New(\"bad type\")\n\tErrBadMajorVersion = errors.New(\"bad major version\")\n\tErrBadMinorVersion = errors.New(\"bad minor version\")\n\tErrMaxDataLen      = errors.New(\"bad tls data len\")\n)\n\nconst (\n\ttlsRecordStateType = iota\n\ttlsRecordStateVersion0\n\ttlsRecordStateVersion1\n\ttlsRecordStateLength0\n\ttlsRecordStateLength1\n\ttlsRecordStateData\n)\n\ntype obfsTLSParser struct {\n\tstep   uint8\n\tstate  uint8\n\tlength uint16\n}\n","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/ginuerzh/gost/blob/a33fdbf4c98034f4bfeeaea9868909822b9c526d/obfs.go#L304-L340","documentation":"ErrBadMinorVersion is returned by the TLS obfs dissector's Parse when the record's minor version byte does not match the expected value (0x01 for the initial ClientHello record, 0x03 afterwards, per tlsVersionMinors). It indicates the stream is not conformant TLS traffic for the expected record sequence.","triggerScenarios":"During Parse at obfs.go:374, in state tlsRecordStateVersion1, the minor-version byte differs from tlsVersionMinors[r.step]; e.g. a ClientHello claiming an unexpected minor version, or garbage/scanner bytes landing in that position.","commonSituations":"Probes/scanners sending random bytes to the otls port; TLS implementations with unusual version negotiation (some middleboxes rewrite version bytes); obfs method mismatch; desynchronized streams from earlier corrupted records.","solutions":["Verify both endpoints use matching otls obfs settings and library versions.","Check for middleboxes/ISPs rewriting TLS record version bytes on the path.","Close and re-establish the connection; the dissector state is unrecoverable after this error.","If caused by scanners, restrict exposure (firewall rules, port knocking, or fallback plain-HTTP camouflage)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// check record minor version byte against expected sequence [0x01,0x03,0x03,0x03]\nexpected := []byte{0x01, 0x03, 0x03, 0x03}\nif int(step) < len(expected) && buf[2] != expected[step] {\n\treturn errors.New(\"unexpected TLS minor version in record header\")\n}","typeGuard":"func minorVersionOK(hdr []byte, step int) bool {\n\tm := []byte{0x01, 0x03, 0x03, 0x03}\n\treturn len(hdr) >= 3 && step < len(m) && hdr[2] == m[step]\n}","tryCatchPattern":"n, err := dissector.Parse(conn, buf)\nif errors.Is(err, dissector.ErrBadMinorVersion) {\n\tconn.Close()\n\treturn fmt.Errorf(\"bad TLS minor version from %s; possible middlebox or scanner\", conn.RemoteAddr())\n}","preventionTips":["Test the full network path for TLS-mutating middleboxes when this error appears on legit traffic.","Use matching library versions so expected version sequences align.","Close and reconnect on this error; never attempt to resync the dissector."],"tags":["obfs","tls","version","protocol-mismatch"],"backgroundTag":"obfs-tls-bad-record-type","analyzedSha":"a33fdbf4c98034f4bfeeaea9868909822b9c526d","analyzedAt":"2026-09-02T22:15:54.506Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}