Table of Contents
List of Examples
Table of Contents
The Arnacon Authentication module provides ENS-based authentication for Kamailio by verifying ENS domain ownership through cryptographic signature validation. This module enables users to authenticate using their ENS domains (e.g., user.cellact.global) instead of traditional username/password combinations.
The module implements a secure authentication flow where clients sign a message containing a UUID and timestamp, and the module verifies that the signature comes from the current owner of the specified ENS domain. This provides strong cryptographic authentication while maintaining compatibility with existing SIP infrastructure.
Key features:
ENS domain-based authentication
ECDSA signature verification using secp256k1
Support for both traditional and wrapped ENS domains
Automatic ENS Name Wrapper detection and handling
Configurable signature timeout for replay attack prevention
Multi-network support (Polygon, Ethereum, custom networks)
The module implements a comprehensive ENS-based authentication system with the following technical features:
The module supports both traditional ENS ownership and wrapped domain ownership:
Direct ownership via ENS Registry contract
Wrapped domain ownership via ENS Name Wrapper contract
Automatic detection of wrapped vs traditional domains
Zero address detection for unregistered domains
Implements Ethereum-style message signing and verification:
Ethereum message prefix handling (\x19Ethereum Signed Message:\n)
ECDSA signature recovery using secp256k1
Address recovery from signature for ownership verification
Timestamp validation to prevent replay attacks
Primary support for Polygon network
Configurable for Ethereum mainnet, testnets, or custom networks
Custom RPC endpoint configuration
Flexible contract address configuration for different networks
The following modules must be loaded before this module:
none
External dependencies:
libcurl - HTTP client library for blockchain RPC calls
libsecp256k1 - cryptographic library for ECDSA signature operations
ENS Registry contract address for the target blockchain network. This contract is used to resolve ENS domain ownership and handle the initial ownership lookup.
Common Addresses:
Polygon: 0x16742E546bF92118F7dfdbEF5170E44C47ae254b
Ethereum Mainnet: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e
Ethereum Sepolia: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e
Default: "0x16742E546bF92118F7dfdbEF5170E44C47ae254b" (Polygon)
Example 1.1. Setting the ens_registry_address parameter
...
modparam("auth_arnacon", "ens_registry_address", "0x16742E546bF92118F7dfdbEF5170E44C47ae254b")
...
RPC endpoint URL for blockchain network communication. Used for all ENS registry and contract calls via JSON-RPC eth_call method. The module automatically detects and interacts with Name Wrapper contracts when needed.
Common Endpoints:
Polygon Mainnet: https://polygon-rpc.com
Ethereum Mainnet: https://eth.drpc.org
Ethereum Sepolia: https://ethereum-sepolia-rpc.publicnode.com
Default: "https://polygon-rpc.com"
Example 1.2. Setting the rpc_url parameter
...
modparam("auth_arnacon", "rpc_url", "https://polygon-rpc.com")
...
Timeout in seconds for signature validation. Signatures older than this timeout will be rejected to prevent replay attacks. The timestamp is extracted from the X-Data header and compared against the current system time.
Recommended Values:
30s - Default, balanced security and usability
60s - More lenient for slower networks
15s - Stricter security for high-security environments
Default: 30
Example 1.3. Setting the signature_timeout parameter
...
modparam("auth_arnacon", "signature_timeout", 30)
...
Enable debug logging for authentication operations. When enabled, detailed information about ENS resolution, signature verification, and authentication steps will be logged. Warning: May log sensitive authentication data.
Values:
0 - Debug disabled
1 - Debug enabled
Default: 0
Authenticates a user by verifying ENS domain ownership through cryptographic signature validation. This function implements the core authentication logic by resolving ENS ownership, recovering the signer's address from the provided signature, and validating that the signer owns the specified ENS domain.
Authentication Flow:
Resolve ENS domain ownership (handling both traditional and wrapped domains)
Extract and validate timestamp from X-Data header
Recover Ethereum address from ECDSA signature
Compare recovered address with ENS domain owner
Parameters:
user_identifier (string) - ENS domain name (e.g., "user.cellact.global") or plain Ethereum address (e.g., "0x1234...abcd")
x_data (string) - X-Data header value in format "UUID:TIMESTAMP" (can be empty to extract from headers)
x_sign (string) - X-Sign header value containing Ethereum signature (can be empty to extract from headers)
Return Type: integer
Return codes:
1 - Authentication successful
-1 - Authentication failed (invalid signature, ENS ownership mismatch, timeout, or error)
This function can be used from REQUEST_ROUTE.
Example 1.5. arnacon_authenticate usage
...
# Basic authentication with explicit parameters
if (arnacon_authenticate("$fU", "$hdr(X-Data)", "$hdr(X-Sign)")) {
xlog("L_INFO", "User $fU authenticated successfully\n");
# Allow registration/call
} else {
xlog("L_ERR", "Authentication failed for $fU\n");
sl_send_reply("403", "Forbidden");
exit;
}
...
...
# Automatic header extraction (pass empty strings)
if (arnacon_authenticate("$fU", "", "")) {
xlog("L_INFO", "ENS domain $fU authenticated\n");
# Proceed with request processing
} else {
sl_send_reply("403", "Forbidden");
exit;
}
...
...
# Complete authentication flow with error handling
route[AUTH] {
# Check if user exists first
if (!arnacon_user_exists("$fU")) {
xlog("L_ERR", "User $fU does not exist\n");
sl_send_reply("404", "User Not Found");
exit;
}
# Authenticate with headers
if (arnacon_authenticate("$fU", "$hdr(X-Data)", "$hdr(X-Sign)")) {
xlog("L_INFO", "User $fU authenticated successfully\n");
return;
} else {
xlog("L_ERR", "Authentication failed for $fU\n");
sl_send_reply("403", "Forbidden");
exit;
}
}
...
Checks if an ENS domain has an owner, effectively verifying if the user exists in the ENS system. This function performs ENS resolution to determine if the domain is registered and has a valid owner address (not the zero address).
Use Case: This function is useful for pre-authentication checks to provide better error messages to clients and avoid unnecessary authentication attempts for non-existent ENS domains.
ENS Resolution: The function handles both traditional ENS ownership through the ENS Registry and wrapped domain ownership through the ENS Name Wrapper contract, automatically detecting the appropriate resolution method.
Parameters:
ens (string) - ENS domain name to check
Return Type: integer
Return codes:
1 - User exists (ENS has a valid owner)
-1 - User does not exist (ENS unregistered, zero owner, or error)
This function can be used from REQUEST_ROUTE.
Example 1.6. arnacon_user_exists usage
...
# Basic user existence check
if (arnacon_user_exists("$fU")) {
xlog("L_INFO", "User $fU exists\n");
# Proceed with authentication
} else {
xlog("L_ERR", "User $fU does not exist\n");
sl_send_reply("404", "User Not Found");
exit;
}
...
...
# Pre-authentication validation
route[PREAUTH] {
if (!arnacon_user_exists("$fU")) {
xlog("L_WARN", "Authentication attempt for non-existent user: $fU\n");
sl_send_reply("404", "User Not Found");
exit;
}
xlog("L_INFO", "User $fU exists, proceeding with authentication\n");
}
...
...
# Registration flow with user existence check
if (is_method("REGISTER")) {
if (!arnacon_user_exists("$fU")) {
sl_send_reply("404", "ENS domain not registered");
exit;
}
# Continue with authentication
route(AUTH);
}
...