shadow1ng/fscan · error

ANO: %w

Error message

ANO: %w

What it means

oracleRawAuth wraps any failure of s.advancedNegotiation() with the "ANO: %w" prefix. Advanced Negotiation Options (ANO) is an optional phase of the Oracle TNS/Two-Task handshake (gated by bits in acfl0/acfl1); failure means the client and server could not agree on ANO services such as encryption, data integrity, or compression.

Source

Thrown at plugins/services/oracle_raw.go:120

	if err != nil {
		return err
	}
	defer conn.Close()

	s := &oracleSession{
		conn:              conn,
		version:           317,
		sessionDataUnit:   0x200000,
		transportDataUnit: 0x200000,
		clrChunkSize:      0x40,
		timeout:           timeout,
	}
	if err := s.connect(ctx, host, port, serviceName); err != nil {
		return err
	}
	if s.acfl0&1 != 0 && s.acfl0&4 == 0 && s.acfl1&8 == 0 {
		if err := s.advancedNegotiation(); err != nil {
			return fmt.Errorf("ANO: %w", err)
		}
	}
	nego, err := s.protocolNegotiation()
	if err != nil {
		return err
	}
	if err := s.dataTypeNegotiation(nego); err != nil {
		return err
	}
	return s.authenticate(nego, host, port, serviceName, username, password)
}

func (s *oracleSession) connect(ctx context.Context, host string, port int, serviceName string) error {
	connectData := oracleConnectData(host, port, serviceName)
	packetLen := 70 + len(connectData)
	if len(connectData) > 230 {
		packetLen = 70
	}

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Read the wrapped inner error for the specific ANO failure (e.g. ora-N code from errorIndex 439)
  2. Disable required encryption/checksum on the server (SQLNET.ENCRYPTION_SERVER=REJECTED) or implement the needed ANO service
  3. Align client with the server's Oracle version's ANO behavior
  4. Retry against a listener without ANO enforcement to isolate the cause

Example fix

// server-side sqlnet.ora before
SQLNET.ENCRYPTION_SERVER = REQUIRED
// after
SQLNET.ENCRYPTION_SERVER = REJECTED  # allow clients without ANO encryption support
Defensive patterns

Strategy: try-catch

Validate before calling

// detect ANO requirement before full auth:
// after connect, inspect s.acfl0/acfl1 flags
if s.acfl0&1 != 0 && s.acfl0&4 == 0 && s.acfl1&8 == 0 {
    log.Println("server requires ANO; lightweight client must support negotiated services")
}

Type guard

func isANOError(err error) bool { return err != nil && strings.HasPrefix(err.Error(), "ANO: ") }

Try / catch

err := oracleRawAuth(ctx, host, port, svc)
if isANOError(err) {
    // unwrap inner cause, adjust server SQLNET encryption/checksum policy or retry without ANO
    return fmt.Errorf("ANO negotiation failed: %w", errors.Unwrap(err))
}

Prevention

When it happens

Trigger: oracleRawAuth connects, sees acfl0&1 set (ANO requested) with acfl0&4==0 and acfl1&8==0, calls advancedNegotiation, and the server's ANO response contains an error code or malformed service data.

Common situations: Server requires Oracle Native Encryption/Checksum that the lightweight client cannot negotiate; version mismatch between client's ANO implementation and server; MITM or middlebox corrupting the ANO exchange.

Related errors


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