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

  1. Fix the offending match directive in the fingerprint file so it contains pattern[/version/...] with a consistent delimiter.
  2. Re-download or restore the stock fingerprint database for the probe file in question.
  3. 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

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


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/54cf3b9b4503eab1. Report an issue: GitHub.