Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Net Dns2 Laravel Package

pear/net_dns2

Net_DNS2 is a pure-PHP DNS resolver for querying A, AAAA, MX, NS, TXT, SRV, SOA and other records over UDP or TCP. It supports IPv4/IPv6, custom nameservers, caching, and detailed response objects, so PHP apps can perform DNS lookups without external extensions.

View on GitHub
Deep Wiki
Context7

Getting Started

pear/net_dns2 is a PEAR-style, non-namespaced PHP DNS client. In Laravel terms it replaces bare dns_get_record() when you need control over which nameserver answers, access to record types PHP hides (SRV, CAA, NAPTR, TLSA), DNSSEC records, or RFC 2136 dynamic updates.

Install it and start with the smallest possible query:

composer require pear/net_dns2
use Net_DNS2_Resolver;
use Net_DNS2_Exception;

$resolver = new Net_DNS2_Resolver([
    'nameservers' => ['1.1.1.1', '8.8.8.8'],
    'timeout'     => 2,
    'retries'     => 2,
]);

try {
    $response = $resolver->query('example.com', 'MX');
} catch (Net_DNS2_Exception $e) {
    report($e);
    return [];
}

foreach ($response->answer as $rr) {
    // $rr->exchange, $rr->preference, $rr->ttl
}

Where to look first:

  • Net_DNS2_Resolver::$options — nameservers, timeout, retries, dns_port, use_tcp, dnssec, cache_type, strict_query.
  • src/Net/DNS2/RR/*.php — one class per record type (Net_DNS2_RR_MX, _TXT, _SRV, _CNAME). Field names live here; this is your real API reference.
  • $response->header->rcode and $response->answer — the two things you check on every call.

First real use case for a Laravel app: validating an email domain before you accept a signup, or before you hand an address to your mail provider.

public function domainAcceptsMail(string $domain): bool
{
    $domain = idn_to_ascii($domain, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46) ?: $domain;

    if ($this->lookup($domain, 'MX')) {
        return true;
    }

    // RFC 5321 implicit MX: no MX record means fall back to A/AAAA
    return (bool) ($this->lookup($domain, 'A') ?: $this->lookup($domain, 'AAAA'));
}

That single method usually pays for the dependency, because dns_get_record() on a misconfigured host returns nothing and you can't tell "no MX" from "resolver timed out."

Implementation Patterns

Bind it once via a service provider

Don't sprinkle new Net_DNS2_Resolver() through controllers. Wrap it behind your own class so tests can swap it — the underlying classes are concrete and network-bound, which makes them untestable directly.

// config/dns.php
return [
    'nameservers' => array_filter(explode(',', env('DNS_NAMESERVERS', '1.1.1.1,8.8.8.8'))),
    'timeout'     => (int) env('DNS_TIMEOUT', 2),
    'retries'     => (int) env('DNS_RETRIES', 2),
    'ttl_floor'   => 60,
];
// app/Providers/DnsServiceProvider.php
public function register(): void
{
    $this->app->singleton(DnsClient::class, fn ($app) => new DnsClient(
        $app['config']->get('dns')
    ));
}

DnsClient holds a Net_DNS2_Resolver and normalises errors into your own exception or an empty result. Everything downstream type-hints DnsClient. In tests, bind a fake that returns canned Net_DNS2_Packet_Response objects or plain arrays.

Domain verification (TXT / CNAME)

The classic SaaS custom-domain flow: user adds a record, you poll until it appears.

public function hasTxt(string $name, string $expected): bool
{
    foreach ($this->lookup($name, 'TXT') as $rr) {
        // ->text is an array of 255-byte chunks; concatenate before comparing
        if (hash_equals($expected, implode('', $rr->text))) {
            return true;
        }
    }
    return false;
}

Do this in a queued job with ->release(30) between attempts, not in a synchronous request. Verification flows are inherently racy with propagation.

Caching (the thing that saves you)

Two options, pick one deliberately:

  1. Built-in file cache — respects TTLs, zero code, survives requests:

    'cache_type' => 'file',
    'cache_file' => storage_path('framework/cache/net_dns2.cache'),
    'cache_size' => 50000,
    

    Caveat: it's a flat file with no locking guarantees under high concurrency, and it's per-host.

  2. Laravel cache — you control the key, TTL, and can negative-cache:

public function lookup(string $name, string $type): array
{
    $key = 'dns:'.strtolower($name).':'.$type;

    return Cache::remember($key, now()->addSeconds(300), function () use ($name, $type) {
        // return a plain serialisable array, NOT the RR objects
    });
}

Never cache the raw Net_DNS2_RR_* objects — they don't serialise cleanly and will bloat Redis. Map to ['type' => 'MX', 'preference' => 10, 'exchange' => '...'] arrays at the boundary. Negative-cache empty results for 30–60s only, so a user who just added their TXT record isn't stuck for five minutes.

Batch DNS work belongs on a queue

Any loop over more than a handful of domains should be a job. Pair it with Laravel's rate limiter so you don't get throttled by Cloudflare or Google:

public function middleware(): array
{
    return [new RateLimited('dns-lookups')];
}

DNSSEC, SRV, and the updater

  • Set 'dnssec' => true to request the DO bit and get RRSIG/DNSKEY/DS records back in $response->answer. Reading signatures is trivial; validating the chain requires configuring trust anchors explicitly and is not on by default. Don't tell auditors you validate DNSSEC unless you've configured anchors and checked $response->header->ad semantics yourself.
  • SRV lookups (_sip._tcp.example.com) are the clean way to do service discovery for a multi-tenant setup; sort by priority then weight manually — the library returns them in wire order.
  • Net_DNS2_Updater speaks RFC 2136 with TSIG. Useful if you run your own BIND/PowerDNS and want to provision records from Laravel instead of shelling out.

Gotchas and Tips

  • Class names are global. Net_DNS2_Resolver, Net_DNS2_Exception, Net_DNS2_RR_* — no namespace. Composer loads them via classmap so autoloading works fine, but if you catch (\Exception) in a broad handler you'll swallow DNS failures silently. Catch Net_DNS2_Exception specifically and log the code.
  • NXDOMAIN is not an exception. A name that doesn't exist returns a response with $response->header->rcode === 'NXDOMAIN' and an empty answer array. So does SERVFAIL, REFUSED, and a valid name with no records of that type. Check rcode explicitly, or you'll treat "server is broken" as "record absent." Turning on strict_query makes empty answer sections throw instead.
  • Empty answer ≠ domain doesn't exist. Always check rcode === 'NOERROR' before concluding a record is missing. CNAME chains also mean the answer you want may be several entries deep — iterate $response->answer looking for $rr->type === 'MX' rather than indexing [0].
  • Default timeout is short and there are retries. For a user-facing request that's fine; for a verification job set timeout to 5 and retries to 2. Log timeouts distinctly from NXDOMAIN — they mean different things operationally and you'll want separate alerting.
  • Nameserver config is implicit in containers. If nameservers is empty, the library reads /etc/resolv.conf and falls back to public resolvers. In Docker/Kubernetes this is usually 127.0.0.11 or a ClusterIP, which may behave differently than your local machine. Always set nameservers explicitly via env.
  • Unicode domains need punycode. idn_to_ascii() before every query; passing münchen.de yields a lookup error, not a helpful message.
  • TCP fallback for big responses. Large TXT/DNSSEC answers get truncated over UDP. The library will retry over TCP, but if you're debugging "missing records," force 'use_tcp' => true once to rule truncation out.
  • The built-in cache file grows and never prunes. If you enable cache_type => 'file', add a scheduled task to delete the file periodically, or prefer the Laravel cache driver where expiry is managed for you.
  • Don't reuse a resolver across Octane requests if you enable caching. The cache state lives on the resolver instance; a singleton with a warm cache is fine for reads but can serve stale data past TTL boundaries under long-lived workers. Prefer Laravel's cache layer with explicit TTLs in Octane contexts.
  • Sorting is your job. MX by preference, SRV by priority then weight, NS alphabetically — the library preserves wire order, which is authoritative for nothing except SRV weighting rules you still have to implement.
  • Testing: never hit the network in the test suite. Because the class is concrete and un-namespaced, mocking it with Mockery::mock('Net_DNS2_Resolver') works but is brittle (the code calls query() and reads public properties). The durable approach is your own DnsClient interface plus a fake that returns arrays; keep a single integration test tagged @group network that exercises the real resolver against example.com.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
alphabalex/messaging-made-easy
rawphp/warp
shootkiran/merobug
narakode/fineauth
numencode/wn-syncops-plugin
ibnnajjaar/mib-global-pay
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator