{"record":{"id":"54cf3b9b4503eab1","repo":"shadow1ng/fscan","slug":"portfinger-match-directive-invalid","errorCode":null,"errorMessage":"portfinger_match_directive_invalid","messagePattern":"portfinger_match_directive_invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/portfinger/match_engine.go","lineNumber":48,"sourceCode":"\trunes := make([]rune, len(b))\n\tfor i, c := range b {\n\t\trunes[i] = rune(c)\n\t}\n\treturn string(runes)\n}\n\n// parseMatchDirective 解析match/softmatch指令的通用实现\nfunc (p *Probe) parseMatchDirective(data, prefix string, isSoft bool) (Match, error) {\n\tmatch := Match{IsSoft: isSoft}\n\n\t// 提取指令文本并解析语法\n\tmatchText := data[len(prefix)+1:]\n\tdirective := p.getDirectiveSyntax(matchText)\n\n\t// 分割文本获取pattern和版本信息\n\ttextSplited := strings.Split(directive.DirectiveStr, directive.Delimiter)\n\tif len(textSplited) == 0 {\n\t\treturn match, fmt.Errorf(\"%s\", i18n.Tr(\"portfinger_match_directive_invalid\", prefix))\n\t}\n\n\tpattern := textSplited[0]\n\tversionInfo := strings.Join(textSplited[1:], \"\")\n\n\t// versionInfo 格式是 \"flags p/product/ v/version/ ...\"\n\t// flags 是正则表达式修饰符(如 s、i、si)，后面跟空格和版本信息字段\n\t// 需要跳过 flags 部分，找到第一个空格开始的版本信息\n\tif idx := strings.Index(versionInfo, \" \"); idx != -1 {\n\t\tversionInfo = versionInfo[idx:]\n\t}\n\n\t// 解码并编译正则表达式\n\tpatternUnescaped, decodeErr := DecodePattern(pattern)\n\tif decodeErr != nil {\n\t\treturn match, decodeErr\n\t}\n","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/core/portfinger/match_engine.go#L30-L66","documentation":"parseMatchDirective splits a match directive string by its delimiter to extract the pattern and version info. If the split yields zero parts, the directive structure is malformed and this error is returned with the directive prefix. It protects the match engine from corrupt probe/match definitions.","triggerScenarios":"Calling getMatch or getSoftMatch with a directive string whose DirectiveStr, when split by the detected delimiter, produces no parts — e.g. an empty or delimiter-only directive body.","commonSituations":"Corrupt or hand-edited port fingerprint databases; files with truncated match lines or a wrong delimiter character; version drift where the fingerprint file format changed.","solutions":["Fix the offending match directive in the fingerprint file so it contains pattern[/version/...] with a consistent delimiter.","Re-download or restore the stock fingerprint database for the probe file in question.","Validate fingerprint files at load time and log/skip malformed directives instead of failing the whole engine."],"exampleFix":"// before\nmatch ssh m|^SSH-2.0-|   // missing pattern/version sections\n// after\nmatch ssh m|^SSH-2.0-([\\w.-]+)| p/OpenSSH/ v/$1/","handlingStrategy":"validation","validationCode":"func directiveLooksValid(prefix, directiveStr string) bool {\n    if directiveStr == \"\" { return false }\n    delim := detectDelimiter(directiveStr)\n    return strings.Count(directiveStr, delim) >= 1\n}","typeGuard":null,"tryCatchPattern":"match, err := p.getMatch(line)\nif err != nil {\n    log.Warnf(\"skipping bad match directive: %v\", err)\n    return nil // continue loading other directives\n}","preventionTips":["Do not hand-edit fingerprint files; keep vendor copies pristine","Validate the probe/match file at startup and report line numbers","Keep fingerprint files in sync with the library version"],"tags":["portscan","fingerprint","parsing"],"backgroundTag":"invalid-argument-format","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}