shadow1ng/fscan · error
portfinger_match_directive_invalid
Error message
portfinger_match_directive_invalid
What it means
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.
Source
Thrown at core/portfinger/match_engine.go:48
runes := make([]rune, len(b))
for i, c := range b {
runes[i] = rune(c)
}
return string(runes)
}
// parseMatchDirective 解析match/softmatch指令的通用实现
func (p *Probe) parseMatchDirective(data, prefix string, isSoft bool) (Match, error) {
match := Match{IsSoft: isSoft}
// 提取指令文本并解析语法
matchText := data[len(prefix)+1:]
directive := p.getDirectiveSyntax(matchText)
// 分割文本获取pattern和版本信息
textSplited := strings.Split(directive.DirectiveStr, directive.Delimiter)
if len(textSplited) == 0 {
return match, fmt.Errorf("%s", i18n.Tr("portfinger_match_directive_invalid", prefix))
}
pattern := textSplited[0]
versionInfo := strings.Join(textSplited[1:], "")
// versionInfo 格式是 "flags p/product/ v/version/ ..."
// flags 是正则表达式修饰符(如 s、i、si),后面跟空格和版本信息字段
// 需要跳过 flags 部分,找到第一个空格开始的版本信息
if idx := strings.Index(versionInfo, " "); idx != -1 {
versionInfo = versionInfo[idx:]
}
// 解码并编译正则表达式
patternUnescaped, decodeErr := DecodePattern(pattern)
if decodeErr != nil {
return match, decodeErr
}
View on GitHub (pinned to 95cc12e753)
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.
Example fix
// before match ssh m|^SSH-2.0-| // missing pattern/version sections // after match ssh m|^SSH-2.0-([\w.-]+)| p/OpenSSH/ v/$1/
Defensive patterns
Strategy: validation
Validate before calling
func directiveLooksValid(prefix, directiveStr string) bool {
if directiveStr == "" { return false }
delim := detectDelimiter(directiveStr)
return strings.Count(directiveStr, delim) >= 1
} Try / catch
match, err := p.getMatch(line)
if err != nil {
log.Warnf("skipping bad match directive: %v", err)
return nil // continue loading other directives
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- portfinger_probe_protocol_invalid
- parser_cidr_failed: %w
- parser_ip_range_failed: %w
- parser_invalid_ip_end_val
- parser_invalid_ip_fmt
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/54cf3b9b4503eab1.
Report an issue: GitHub.