PEAR is archived and read-only

This mirror preserves historical PEAR package releases and metadata so existing references remain available.

Home » Networking » Net_DNS » Manual

Provides methods for parsing and manipulating DNS packets as returned from DNS servers and provides communication methods for sending and receiving DNS packets.

Introduction

Introduction – General purpose DNS querying and packet parsing

Contributors

Description

The Net_DNS class provides DNS packet manipulation methods and the ability to send and receive packets to/from nameservers. Any type of DNS packet can be created, including RFC 2136 style DNS UPDATE packets.

The current list of supported RR types are:

Class Summary Net_DNS

Class Summary Net_DNS – DNS Packet manipulation class

DNS Packet manipulation class

This class includes sub-classses that provide methods for creating, parsing, sending, and receving DNS nameserver packets.

This class is only a container class and generally should never be constructed. It contains constants defined in RFC 1035 with methods for converting between the integer and the name values of such constants.

For information on sending a basic query to a nameserver for a specific record, see Net_DNS_Resolver::query().

Class Summary Net_DNS_Resolver

Class Summary Net_DNS_Resolver – Provides a resolver implementation to handle DNS queries

Net_DNS_Resolver

The resolver class a high level interface for communicating with DNS servers. It uses the UNIX system stub resolver configuration files (if available) to configure the resolver. The resolver can also be configured manually by overriding the system configuration. This is done by setting the appropriate values in the Net_DNS_Resolver object. See Net_DNS_Resolver::query() for more information on the resolver configuration.

Net_DNS_Resolver::query()

Net_DNS_Resolver::query() – Queries a nameserver and returns a response

Synopsis

require_once('Net/DNS.php');

Net_DNS_Packet Net_DNS_Resolver::query ( string $hostname , string $type = 'A' , string $class = 'IN' )

Description

Constructs a DNS query packet and forwards the query to a nameserver configured in the system stub resolver (ie. /etc/resolv.conf). When a response is received from the DNS server, a fully populated Net_DNS_Packet object is returned that represents the response.

The resolver object contains many properties that control that behaviour of the resolver. Some of these settings are automatically read from the system resolver configuration if available. On Linux/UNIX based systems, this includes /etc/resolv.conf as well as various environment variables. This configuration is done at the time of object instantiation and can be overridden by setting the appropriate object properties.

This function will only return a Net_DNS_Packet if the ANSWER section contains resource records. Specifically, if the ANCOUNT variable in the DNS packet header is 0, query() will return 0 (note: 0, not FALSE). If you are expecting a packet without resource records in the ANSWER section, use Net_DNS_Resolver::rawQuery(). This is useful when doing manual recursion.

For a description of the returned RR data object, see Net_DNS_RR.

Resolver Configuration Object Properties:

Environment Variables:

Example

Using Net_DNS_Resolver::query()

<?php
require_once 'Net/DNS.php';

$resolver = new Net_DNS_Resolver();
$response = $resolver->query('example.com');
if ($response) {
  foreach ($response->answer as $rr) {
    $rr->display();
  }
}
?>

Output:

    
example.com.            129808  IN      A       192.0.34.166

The following example shows a DNS query for an MX record. Note that the IP address for the mail exchanger listed within the zone is returned with the response in the additional section. The second exchanger (that is not inside this zone) is not listed. To receive this address, you must perform another query specifically for the A record using the returned hostname.

Using Net_DNS_Resolver::query() to look up an MX record

<?php
require_once 'Net/DNS.php';

$resolver = new Net_DNS_Resolver();
$response = $resolver->query('php.net', 'MX');
if ($response) {
  foreach ($response->answer as $rr) {
    $rr->display();
  }
  if (count($response->additional)) {
    foreach ($response->additional as $rr) {
      $rr->display();
    }
  }
}
?>

Output:

    
php.net.                86121   IN      MX      15 smtp.osuosl.org.
php.net.                86121   IN      MX      5 osu1.php.net.
osu1.php.net.           86121   IN      A       140.211.166.39

The next example shows a more complex query with debugging information enabled. Note that the usevc option is set to TRUE. This forces the resolver to use TCP instead of UDP. This can be seen in the debug output on the send_tcp() line.

Using Net_DNS_Resolver::query() with specific nameservers and options

<?php
require_once 'Net/DNS.php';

$resolver = new Net_DNS_Resolver();
$resolver->debug = 1; // Turn on debugging output to show the query
$resolver->usevc = 1; // Force the use of TCP instead of UDP
$resolver->nameservers = array(              // Set the IP addresses
                           '198.41.0.4',     // of the nameservers
                           '192.228.79.201'  // to query.
                           );
$response = $resolver->query('example.com');
if (! $response) {
  echo "\n";
  echo "ANCOUNT is 0, therefore the query() 'failed'\n";
  echo "See Net_DNS_Resolver::rawQuery() to receive this packet\n";
}
?>

Output:

    
;; query(example.com, A, IN)
;; send_tcp(198.41.0.4:53)
;; sending 29 bytes
;; received 517 bytes
;; HEADER SECTION
;; id = 58298
;; qr = 1    opcode = QUERY    aa = 0    tc = 0    rd = 1
;; ra = 0    rcode  = NOERROR
;; qdcount = 1  ancount = 0  nscount = 13  arcount = 15

;; QUESTION SECTION (1 record)
;;
;example.com.   IN      A

;; ANSWER SECTION (0 records)

;; AUTHORITY SECTION (13 records)
com.            172800  IN      NS      A.GTLD-SERVERS.NET.
com.            172800  IN      NS      G.GTLD-SERVERS.NET.
com.            172800  IN      NS      H.GTLD-SERVERS.NET.
com.            172800  IN      NS      C.GTLD-SERVERS.NET.
com.            172800  IN      NS      I.GTLD-SERVERS.NET.
com.            172800  IN      NS      B.GTLD-SERVERS.NET.
com.            172800  IN      NS      D.GTLD-SERVERS.NET.
com.            172800  IN      NS      L.GTLD-SERVERS.NET.
com.            172800  IN      NS      F.GTLD-SERVERS.NET.
com.            172800  IN      NS      J.GTLD-SERVERS.NET.
com.            172800  IN      NS      K.GTLD-SERVERS.NET.
com.            172800  IN      NS      E.GTLD-SERVERS.NET.
com.            172800  IN      NS      M.GTLD-SERVERS.NET.

;; ADDITIONAL SECTION (15 records)
A.GTLD-SERVERS.NET.     172800  IN      AAAA    2001:503:a83e::2:30
A.GTLD-SERVERS.NET.     172800  IN      A       192.5.6.30
G.GTLD-SERVERS.NET.     172800  IN      A       192.42.93.30
H.GTLD-SERVERS.NET.     172800  IN      A       192.54.112.30
C.GTLD-SERVERS.NET.     172800  IN      A       192.26.92.30
I.GTLD-SERVERS.NET.     172800  IN      A       192.43.172.30
B.GTLD-SERVERS.NET.     172800  IN      AAAA    2001:503:231d::2:30
B.GTLD-SERVERS.NET.     172800  IN      A       192.33.14.30
D.GTLD-SERVERS.NET.     172800  IN      A       192.31.80.30
L.GTLD-SERVERS.NET.     172800  IN      A       192.41.162.30
F.GTLD-SERVERS.NET.     172800  IN      A       192.35.51.30
J.GTLD-SERVERS.NET.     172800  IN      A       192.48.79.30
K.GTLD-SERVERS.NET.     172800  IN      A       192.52.178.30
E.GTLD-SERVERS.NET.     172800  IN      A       192.12.94.30
M.GTLD-SERVERS.NET.     172800  IN      A       192.55.83.30

ANCOUNT is 0, therefore the query() 'failed'
See Net_DNS_Resolver::rawQuery() to receive this packet

Note

This function can not be called statically.

Net_DNS_Resolver::rawQuery()

Net_DNS_Resolver::rawQuery() – Queries a nameserver and returns a response

Synopsis

require_once('Net/DNS.php');

Net_DNS_Packet Net_DNS_Resolver::rawQuery ( string $hostname , string $type = 'A' , string $class = 'IN' )

Description

The Net_DNS_Resolver::rawQuery() function performs a DNS query similar to the Net_DNS_Resolver::query() function; however, rawQuery() will return any response from the nameserver. This is useful when the response packet may or may not contain any resource records in the "ANSWER" section.

rawQuery() uses the same resolver configuration used by Net_DNS_Resolver::query().

For a description of the returned RR data object, see Net_DNS_RR.

Example

Using Net_DNS_Resolver::rawQuery()

<?php
require_once 'Net/DNS.php';

$resolver = new Net_DNS_Resolver();
$response = $resolver->rawQuery('example.com');
if ($response) {
  if (count($response->answer)) {
    foreach ($response->answer as $rr) {
      $rr->display();
    }
  }
}
?>

Output:

    
example.com.            129808  IN      A       192.0.34.166

Note

This function can not be called statically.

Net_DNS_Resolver::axfr()

Net_DNS_Resolver::axfr() – Performs a zone transfer from a nameserver

Synopsis

require_once('Net/DNS.php');

Net_DNS_Packet Net_DNS_Resolver::axfr ( string $dname , string $class = 'IN' , boolean $old = FALSE )

Description

axfr() attempts a zone transfer from the nameservers specified in the Net_DNS_Resolver->nameservers array. Net_DNS_Resolver::axfr() uses the same resolver configuration as the Net_DNS_Resolver::query() method.

Most public nameservers will not allow a zone transfer by default. A zone transfer will provide a full list of DNS resource records inside of a zone file. A zone transfer will always use TCP instead of UDP queries.

For a description of the returned RR data object, see Net_DNS_RR.

Example

Failed Net_DNS_Resolver::axfr() query

<?php
require_once 'Net/DNS.php';

$resolver = new Net_DNS_Resolver();
$resolver->debug = 1;
$response = $resolver->axfr('example.com');
print_r($response);
if (count($response) == 0) {
  echo "\n";
  echo "AXFR Failed\n";
}
?>

Output:

    
;; axfr_start(example.com, IN)
;; query(example.com, AXFR, IN)
;; axfr_start(192.168.0.254:53)
;; sending 29 bytes
;; read_tcp: expecting 2 bytes
;; read_tcp: received 2 bytes
;; read_tcp: expecting 29 bytes
;; read_tcp: received 29 bytes
;; received 29bytes
;; HEADER SECTION
;; id = 29190
;; qr = 1    opcode = QUERY    aa = 0    tc = 0    rd = 1
;; ra = 1    rcode  = NOTAUTH
;; qdcount = 1  ancount = 0  nscount = 0  arcount = 0

;; QUESTION SECTION (1 record)
;;
;example.com.   IN      AXFR

;; ANSWER SECTION (0 records)

;; AUTHORITY SECTION (0 records)

;; ADDITIONAL SECTION (0 records)
Array
(
)

AXFR Failed

In the following example, debugging has been turned on and the nameserver has been configured to allow zone transfers. The most important item of note in this example is the SOA record at the beginning and end of the returned records. When a name server sends a zone transfer, the first record sent is the SOA record. The zone transfer is considered complete when the name server sends the SOA record again. This behaviour can be seen in the debug output. The resulting array returned by axfr() does not return the final SOA record.

Succesful Net_DNS_Resolver::axfr() query

<?php
require_once 'Net/DNS.php';

$resolver = new Net_DNS_Resolver();
$resolver->debug = 1;
$response = $resolver->axfr('my.example.com');
echo "\n\nThe following resource records were returned from the nameserver:\n";
if (count($response)) {
  foreach ($response as $rr) {
    $rr->display();
  }
}
?>

Output:

    
;; axfr_start(my.example.com, IN)
;; query(my.example.com, AXFR, IN)
;; axfr_start(192.168.0.254:53)
;; sending 32 bytes
;; read_tcp: expecting 2 bytes
;; read_tcp: received 2 bytes
;; read_tcp: expecting 262 bytes
;; read_tcp: received 262 bytes
;; received 262bytes
;; HEADER SECTION
;; id = 21220
;; qr = 1    opcode = QUERY    aa = 1    tc = 0    rd = 0
;; ra = 1    rcode  = NOERROR
;; qdcount = 1  ancount = 10  nscount = 0  arcount = 0

;; QUESTION SECTION (1 record)
;;
;my.example.com.        IN      AXFR

;; ANSWER SECTION (10 records)
my.example.com.         300     IN      SOA     ns1.my.example.com. hostmaster.my.example.com. 103 3600 1800 2592000 300
my.example.com.         300     IN      NS      ns1.my.example.com.
my.example.com.         300     IN      MX      10 mx1.my.example.com.
my.example.com.         300     IN      MX      20 mx2.my.example.com.
my.example.com.         300     IN      A       192.168.0.1
mx1.my.example.com.     300     IN      A       192.168.0.2
mx2.my.example.com.     300     IN      A       192.168.0.3
server.my.example.com.  300     IN      CNAME   www.my.example.com.
www.my.example.com.     300     IN      A       192.168.0.1
my.example.com.         300     IN      SOA     ns1.my.example.com. hostmaster.my.example.com. 103 3600 1800 2592000 300

;; AUTHORITY SECTION (0 records)

;; ADDITIONAL SECTION (0 records)


The following resource records were returned from the nameserver:
my.example.com.         300     IN      SOA     ns1.my.example.com. hostmaster.my.example.com. 103 3600 1800 2592000 300
my.example.com.         300     IN      NS      ns1.my.example.com.
my.example.com.         300     IN      MX      10 mx1.my.example.com.
my.example.com.         300     IN      MX      20 mx2.my.example.com.
my.example.com.         300     IN      A       192.168.0.1
mx1.my.example.com.     300     IN      A       192.168.0.2
mx2.my.example.com.     300     IN      A       192.168.0.3
server.my.example.com.  300     IN      CNAME   www.my.example.com.
www.my.example.com.     300     IN      A       192.168.0.1

Note

This function can not be called statically.

Class Summary Net_DNS_Packet

Class Summary Net_DNS_Packet – Provides an object abstraction of a DNS packet

Net_DNS_Packet

The Net_DNS_Packet class provides methods for creating a DNS packet suitable for sending to a nameserver. It also provides the methods of parsing a response from a nameserver into a Net_DNS_Packet object.

A standard DNS packet is made up of five main pieces:

Net_DNS defines the DNS packet header as a Net_DNS_Header object. Net_DNS_Question defines the question section of a packet object. The remaining three sections should be arrays of Net_DNS_RR objects.

Class Summary Net_DNS_RR

Class Summary Net_DNS_RR – Provides resource record parsing and creation

Net_DNS_RR

The Net_DNS_RR class provides methods of parsing resource records returned by a nameserver, creation of resource record objects to be sent to a nameserver, and the ability to access each component of an RR as an object property.

Each resource record object MUST contain the following properties:

If type is a supported RR type, it will automatically be decompressed and/or decoded into its appropriate property values. The values inside of an RR object will vary based on the type of RR.

Supported RR types:

Examples -- DNS Updates

Examples -- DNS Updates – RFC 2136 DNS Updates

RFC 2136 DNS Updates

By constructing a specially formatted DNS packet and sending it to a nameserver, a dynamic DNS update can be performed very easily. RFC 2136 defines some variations of a DNS packet that are used by Net_DNS to request an update. The nameserver must first be configured to accept DNS updates, a key must be established between the client and server, and most importantly, the PHP mhash extension must be included for processing the MD5 digest of the key.

The format of the DNS packet is very specific and requires in-depth knowledge of how DNS updates work. Net_DNS currently does not support any abstraction of these specially formatted packets. Packets must currently be crafted and sent manually. The full formatting of update packets can be found in RFC 2136.

For a complete listing of all of the fields that are available for DNS updates, please review RFC2136 (http://www.ietf.org/rfc/rfc2136.txt). The following examples show the simplest forms of a DNS update.

Sending a dynamic DNS update packet to a nameserver

<?php
require_once 'Net/DNS.php';

$resolver = new Net_DNS_Resolver();

// We should only send the request to the master server
// accepting DNS updates for the zone.
$resolver->nameservers = array('192.168.0.254');

// We must manually construct the DNS packet for a DNS update
// First we must instantiate the packet object
$packet = new Net_DNS_Packet();

// Create the header for the update packet.  Most of the defaults are
// acceptable, but we must set the header OPCODE to "UPDATE"
$packet->header = new Net_DNS_Header();
$packet->header->id = $resolver->nextid();
$packet->header->qr = 0;
$packet->header->opcode = "UPDATE";

// As specified in RFC2136, the question section becomes the "ZONE" section.
// This specifies the zone for which we are requesting a change.  This
// reflects the zone configuration as specified in the nameserver
// configuration.
$packet->question[0] = new Net_DNS_Question('example.com', "SOA", "IN");

// The "ANSWER" section of the packet becomes the "PREREQUISITE" section of
// the packet. Section 2.4 of RFC2136 defines the possible values for this
// section.  As show below, without any prerequisites the nameserver will
// attempt to perform the update unconditionally.
$packet->answer = array();

// The AUTHORITY section becomes the "UPDATE" section of the DNS packet.  The
// UPDATE section is a collection of resource record updates that should be
// modified in one form or another.  RRs can be deleted or added based on the
// values passed in the RR object.  These values are specified in RFC2136 but
// are summarized here:
//
// Adding an RR
// A complete RR object with a non-zero TTL is considered an addition.
//
// Deleting an RR
// A complete RR object with a zero TTL is considered an deletion. An RR that
// matches (exactly) with all values except for the TTL will be removed.
//
// Deleting an RRset
// A complete RR object with a zero TTL and a type of ANY is considered a
// deletion of all RRs with the specified name and type. An RR that matches
// (exactly) with all values except for the TTL and the TYPE will be removed.
//
// Deleting all RRsets for a name 
// A complete RR object with a zero TTL, a type of ANY, and a class of ANY is
// considered a deletion of all RRs with the specified name. Any RR that
// matches the name section of the query will be removed.
//
// The following specification will delete the RR that has a name of
// "example.com", class of "IN", type of "A", and an address of
// "192.0.34.166".
$rrDelete =& Net_DNS_RR::factory("example.com. 0 IN A 192.0.34.166");
//
// The following specification will add an RR that has a name of example.com,
// a TTL of 1 hour, a class of "IN", type of "A", and an address of
// "192.0.34.155").  Note that the only difference between this RR and the
// previous RR is the value of the TTL.
$rrAdd =& Net_DNS_RR::factory("example.com. 3600 IN A 192.0.34.166");
//
// The RR modifications are added to the authority (UPDATE) section of the DNS
// packet.
$packet->authority[0] = $rrDelete;
$packet->authority[1] = $rrAdd;
//
// The signature must be present in any packet sent to a nameserver that
// requires authentication.  The TSIG RR is added to the additional section of
// the DNS packet.
$tsig =& Net_DNS_RR::factory("keyname.as.specified.in.server. TSIG ThisIsMyKey");
$packet->additional = array($tsig);
// Net_DNS does not automatically calculate the number of records stored in
// each section.  This calculation must be done manually.
$packet->header->qdcount = count($packet->question);
$packet->header->ancount = count($packet->answer);
$packet->header->nscount = count($packet->authority);
$packet->header->arcount = count($packet->additional);
//
// After creating your packet, you must send it to the name server for
// processing.  DNS updates must use the send_tcp() method: 
$response = $resolver->send_tcp($packet, $packet->data());
//
// The response from the server will vary.  If the update was successfuly, the
// server will have a response code of "NOERROR".  Any other error types will
// be reported in the response packet's header "rcode" variable.
if ($response->header->rcode != "NOERROR") {
  return($response->header->rcode);
}

?>