shadow1ng/fscan · error

ANO

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.

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.

Appendix: 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)