CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pycares

Python interface for c-ares asynchronous DNS library

Pending
Overview
Eval results
Files

dns-queries.mddocs/

DNS Queries

Comprehensive DNS query operations supporting all major record types including A, AAAA, MX, TXT, SOA, SRV, and others. All queries are asynchronous and use callback-based completion notification.

Capabilities

Query Operations

Perform DNS queries for specific record types. Supports both direct queries and search-based queries that use configured search domains.

def query(self, name: str, query_type: int, callback, query_class: Optional[int] = None) -> None:
    """
    Perform a DNS query for a specific record type.
    
    Args:
        name: str - Domain name to query
        query_type: int - DNS record type (QUERY_TYPE_* constants)
        callback: Callable - Function called with (result, error) when complete
        query_class: Optional[int] - DNS class (default: QUERY_CLASS_IN)
        
    Raises:
        TypeError: If callback is not callable
        ValueError: If query_type or query_class is invalid
        RuntimeError: If channel is destroyed
    """

def search(self, name: str, query_type: int, callback, query_class: Optional[int] = None) -> None:
    """
    Perform a DNS search query using configured search domains.
    
    Similar to query() but will try appending search domains if the initial
    query fails and the name doesn't contain enough dots (controlled by ndots).
    
    Args:
        name: str - Domain name to search for
        query_type: int - DNS record type (QUERY_TYPE_* constants)  
        callback: Callable - Function called with (result, error) when complete
        query_class: Optional[int] - DNS class (default: QUERY_CLASS_IN)
        
    Raises:
        TypeError: If callback is not callable
        ValueError: If query_type or query_class is invalid
        RuntimeError: If channel is destroyed
    """

Usage Example:

import pycares

def query_callback(result, error):
    if error is not None:
        print(f'DNS Error: {pycares.errno.strerror(error)}')
        return
        
    if isinstance(result, list):
        for record in result:
            print(f'{record.type} record: {record}')
    else:
        print(f'{result.type} record: {result}')

channel = pycares.Channel()

# Direct query for A records
channel.query('google.com', pycares.QUERY_TYPE_A, query_callback)

# Search query with domain search
channel.search('mail', pycares.QUERY_TYPE_MX, query_callback)

# Query for TXT records
channel.query('google.com', pycares.QUERY_TYPE_TXT, query_callback)

Query Types

DNS record types supported for queries:

# IPv4 address records
QUERY_TYPE_A = 1

# IPv6 address records  
QUERY_TYPE_AAAA = 28

# Canonical name records
QUERY_TYPE_CNAME = 5

# Mail exchange records
QUERY_TYPE_MX = 15

# Text records
QUERY_TYPE_TXT = 16

# Name server records
QUERY_TYPE_NS = 2

# Pointer records (reverse DNS)
QUERY_TYPE_PTR = 12

# Start of authority records
QUERY_TYPE_SOA = 6

# Service location records
QUERY_TYPE_SRV = 33

# Certification Authority Authorization records
QUERY_TYPE_CAA = 257

# Naming Authority Pointer records
QUERY_TYPE_NAPTR = 35

# Query for any available record type
QUERY_TYPE_ANY = 255

Query Classes

DNS query classes (rarely needed, defaults to IN):

# Internet class (default)
QUERY_CLASS_IN = 1

# CHAOS class
QUERY_CLASS_CHAOS = 3

# Hesiod class
QUERY_CLASS_HS = 4

# None class
QUERY_CLASS_NONE = 254

# Any class
QUERY_CLASS_ANY = 255

Result Types

Each DNS record type returns specific result objects with relevant attributes:

A Record Results

class ares_query_a_result:
    """IPv4 address record result."""
    type = 'A'
    host: str      # IPv4 address as string
    ttl: int       # Time to live in seconds

AAAA Record Results

class ares_query_aaaa_result:
    """IPv6 address record result."""
    type = 'AAAA'
    host: str      # IPv6 address as string
    ttl: int       # Time to live in seconds

CNAME Record Results

class ares_query_cname_result:
    """Canonical name record result."""
    type = 'CNAME'
    cname: str     # Canonical name
    ttl: int       # Time to live (-1 if not available)

MX Record Results

class ares_query_mx_result:
    """Mail exchange record result."""
    type = 'MX'
    host: str      # Mail server hostname
    priority: int  # Mail server priority (lower = higher priority)
    ttl: int       # Time to live (-1 if not available)

TXT Record Results

class ares_query_txt_result:
    """Text record result."""
    type = 'TXT'
    text: str      # Text content
    ttl: int       # Time to live (-1 if not available)

NS Record Results

class ares_query_ns_result:
    """Name server record result."""
    type = 'NS'
    host: str      # Name server hostname
    ttl: int       # Time to live (-1 if not available)

PTR Record Results

class ares_query_ptr_result:
    """Pointer record result."""
    type = 'PTR'
    name: str      # Domain name
    ttl: int       # Time to live (-1 if not available)
    aliases: list[str]  # List of aliases

SOA Record Results

class ares_query_soa_result:
    """Start of authority record result."""
    type = 'SOA'
    nsname: str    # Primary name server
    hostmaster: str # Responsible person's email
    serial: int    # Serial number
    refresh: int   # Refresh interval in seconds
    retry: int     # Retry interval in seconds
    expires: int   # Expiration time in seconds
    minttl: int    # Minimum TTL in seconds
    ttl: int       # Time to live (-1 if not available)

SRV Record Results

class ares_query_srv_result:
    """Service record result."""
    type = 'SRV'
    host: str      # Target hostname
    port: int      # Service port number
    priority: int  # Priority (lower = higher priority)
    weight: int    # Weight for load balancing
    ttl: int       # Time to live (-1 if not available)

CAA Record Results

class ares_query_caa_result:
    """Certification Authority Authorization record result."""
    type = 'CAA'
    critical: int  # Critical flag (0 or 1)
    property: str  # Property name (e.g., 'issue', 'issuewild', 'iodef')
    value: str     # Property value
    ttl: int       # Time to live (-1 if not available)

NAPTR Record Results

class ares_query_naptr_result:
    """Naming Authority Pointer record result."""
    type = 'NAPTR'
    order: int        # Order preference
    preference: int   # Preference within same order
    flags: str        # Flags string
    service: str      # Service parameters
    regex: str        # Regular expression
    replacement: str  # Replacement string
    ttl: int         # Time to live (-1 if not available)

Usage Examples

A Record Lookup

def a_record_callback(result, error):
    if error:
        print(f'Error: {pycares.errno.strerror(error)}')
        return
        
    for record in result:
        print(f'A record: {record.host} (TTL: {record.ttl})')

channel.query('google.com', pycares.QUERY_TYPE_A, a_record_callback)

MX Record Lookup

def mx_record_callback(result, error):
    if error:
        print(f'Error: {pycares.errno.strerror(error)}')
        return
        
    # Sort by priority (lower number = higher priority)
    mx_records = sorted(result, key=lambda x: x.priority)
    
    for record in mx_records:
        print(f'MX record: {record.host} (priority: {record.priority})')

channel.query('google.com', pycares.QUERY_TYPE_MX, mx_record_callback)

TXT Record Lookup

def txt_record_callback(result, error):
    if error:
        print(f'Error: {pycares.errno.strerror(error)}')
        return
        
    for record in result:
        print(f'TXT record: {record.text}')

channel.query('google.com', pycares.QUERY_TYPE_TXT, txt_record_callback)

ANY Query (Multiple Record Types)

def any_query_callback(result, error):
    if error:
        print(f'Error: {pycares.errno.strerror(error)}')
        return
        
    for record in result:
        if record.type == 'A':
            print(f'A: {record.host}')
        elif record.type == 'AAAA':
            print(f'AAAA: {record.host}')
        elif record.type == 'MX':
            print(f'MX: {record.host} (priority: {record.priority})')
        elif record.type == 'TXT':
            print(f'TXT: {record.text}')
        else:
            print(f'{record.type}: {record}')

channel.query('google.com', pycares.QUERY_TYPE_ANY, any_query_callback)

Reverse DNS Lookup (PTR)

def ptr_callback(result, error):
    if error:
        print(f'Error: {pycares.errno.strerror(error)}')
        return
        
    for record in result:
        print(f'PTR: {record.name}')
        if record.aliases:
            print(f'Aliases: {", ".join(record.aliases)}')

# Reverse lookup for IP address
channel.query('8.8.8.8.in-addr.arpa', pycares.QUERY_TYPE_PTR, ptr_callback)

Error Handling

All query callbacks receive an error parameter. Common DNS errors include:

  • ARES_ENOTFOUND: Domain name not found
  • ARES_ETIMEOUT: Query timed out
  • ARES_ESERVFAIL: DNS server failure
  • ARES_ENODATA: No data in response
  • ARES_ECANCELLED: Query was cancelled

See Error Handling for complete error code documentation.

Install with Tessl CLI

npx tessl i tessl/pypi-pycares

docs

channel-management.md

dns-queries.md

error-handling.md

host-resolution.md

index.md

utilities.md

tile.json