Using PHP to Perform DNS Lookups

Posted by Nessa | Posted in uncategorized | Posted on 30-06-2010

15

PHP has a couple DNS functions you can use to perform record lookups.

Most of us are familiar with the two basic ones – gethostbyname() and gethostbyaddr(), both of which perform a single function – returning a hostname or IP address. Here’s an example of both:

<?php

$ip = gethostbyname("v-nessa.net");
$host = gethostbyaddr("69.174.114.71");

echo "v-nessa.net has the IP $ip, which reverses to $host";
?>

The above will return:

v-nessa.net has the IP 69.174.114.71, which has a PTR of server.v-nessa.net

Similarly to gethostbyname, there’s gethostbynamel which is useful for hostnames with multiple A records:

$ips = gethostbynamel("test.v-nessa.net");
foreach ($ips as $ip => $value){
echo $value . "\n";
}

Will return:

69.174.114.71
69.174.115.243

A more advanced function is dns_get_record, which can pull any valid record for a hostname or IP.  Think about the dig command you use in Unix to find DNS records:

nessa@nessa-desktop:~$ dig +short v-nessa.net A
69.174.114.71

The dns_get_record function works in a similar way, and can obtain the following DNS record types:

DNS_A, DNS_CNAME, DNS_HINFO, DNS_MX, DNS_NS, DNS_PTR, DNS_SOA, DNS_TXT, DNS_AAAA, DNS_SRV, DNS_NAPTR, DNS_A6, DNS_ALL or DNS_ANY.

The following will give you a similar result:

$recs = dns_get_record("v-nessa.net", DNS_A);
print_r($recs);

Will return:

Array
(
[0] => Array
(
[host] => v-nessa.net
[type] => A
[ip] => 69.174.114.71
[class] => IN
[ttl] => 13728
)
)

If you want to obtain multiple DNS types, you can do so by separating the record types with a plus sign:

$recs = dns_get_record("v-nessa.net", DNS_A + DNS_MX);

Will return:

Array
(
[0] => Array
(
[host] => v-nessa.net
[type] => A
[ip] => 69.174.114.71
[class] => IN
[ttl] => 13736
)

[1] => Array
(
[host] => v-nessa.net
[type] => MX
[pri] => 0
[target] => v-nessa.net
[class] => IN
[ttl] => 14145
)

)

You’ll notice that the output is a double array, so to call individual values you can do either of the following:

// will return the IP for array 0 ( A record)

echo $recs[0]['ip'];

// will return results for common records

foreach ($recs as $type => $value){
echo $value[ip] . "\n";
}

Similar to the example above, you can use the DNS_ALL type to show any records available for the hostname, and use a minus sign to exclude certain record types. For example, the below code will return all DNS results for v-nessa.net, but exclude NS records:

$recs = dns_get_record("v-nessa.net", DNS_ALL - DNS_NS );

foreach ($recs as $type => $value){
echo $value[type] . "\n";
}

The following records were returned:

A
SOA
MX
TXT

Here’s a more practical example – a simple PHP DNS lookup script. Say you have a form on your site that allows a user to type in a hostname and select a type of record: A, MX, NS, and TXT. The passed form values are $host and $type, and the below script will accept the variables and output the results according to the record type:

HTML Form:

<form action="dns.php" method="POST">
Hostname: <input type="text" name="host" />
Type: <select name="type">
<option value="a">A</option>
<option value="mx">MX</option>
<option value="ns">NS</option>
<option value="txt">TXT</option> </select>
</form>

PHP Script (dns.php):

<?php

if(!empty($_POST['host']) && !empty($_POST['type'])){

    // Grab variable from form and define valid types

    $host = $_POST['host'];
    $type = strtoupper($_POST['type');
    $validtypes=array("A","MX","NS","TXT");

    // Check that dns type is defined or allowed

    if(!defined("DNS_" . $type) or !in_array($type,$validtypes)){
       echo "Invalid DNS Type!";
    }else{

       $type = constant("DNS_" . $type);
       $rec = dns_get_record($host, $type);

       // Set result types - can be modified by using available elements from $rec array

       switch($type){
             case DNS_A:
                    $recvals=array("Hostname" => "host","Type" => "type", "IP" => "ip");
                    break;
             case DNS_MX:
                    $recvals=array("Hostname" => "host","Type" => "type", "Target" => "target", "Priority" => "pri");
                    break;
             case DNS_NS:
                    $recvals=array("Hostname" => "host","Type" => "type", "Target" => "target");
                    break;
             case DNS_TXT:
                    $recvals=array("Hostname" => "host","Type" => "type", "Record" => "txt");
                    break;
        }

      // Output results

      foreach ($rec as $arr => $num){
             foreach ($recvals as $title => $value){
                    echo $title . " : " . $num[$value] . "\n";
             }
      }

    }
} else {

     echo "Either hostname or record type is missing";
}

It’s of course easy to modify the above code accordingly, and I’m sure there may be better ways to do this. Feel free to post your own code snippets or comments.

MX Validation in PHP

Posted by Nessa | Posted in Uncategorized | Posted on 01-12-2007

9

Hosting companies have all kinds of tactics to keep spam away from their customers, but one very common complaint I get is the amount of spam coming in through contact forms. Even though we don’t allow ‘nobody’ mail through the php mail() function and we provide the best server-side spam filters available, local mail cannot be filtered or limited. In other words, no spam filter in the world is going to save you from your shitty contact form.

I started recommending to our customers to implement MX checks in their forms as spam bots nowadays can easily get past things like captcha and textual confirmations. Spammers rarely send email from valid mail hosts so it’s very easy to filter these out with just a few lines of code:

<?php
list($user, $domain) = split(“@”, $email);
if (checkdnsrr($domain, “MX”)) {
} else {
}

?>

To explain the code a little bit, you’re basically taking your stored email address variable ($email) and using the split() function to single out the domain name into one variable, $domain. When you pass the domain through the checkdnsrr() function, PHP will return either a ’1′ or ’0′ result, which is interpreted as either true or false. The above is just the basic code, but you can have it spit out errors as well:

if (checkdnsrr($domain, “MX”)) {
} else {
echo "Invalid email";
}

The checkdnsrr() function can also be used to check for other records as well, like A, CNAME, NS, etc.

VirtualHost Hacking with Wildcard DNS

Posted by Nessa | Posted in Uncategorized | Posted on 19-05-2007

7

A recent topic in the webhosting business is wildcard DNS.  Setting up a wildcard record will allow you to essentially have infinite subdomains all pointing to the same place…. you can try this on my site if you’d like by typing in any random subdomain (like lkjairl.v-nessa.net) and then see if point back to my primary, unless it’s one that I’ve actually created.  Now if you combine this ‘technology’ with the power of .htaccess rewrites, then congratulations.  You’ve just cheated your host and obtained unlimited subdomains.

The first thing you would need to do is have a wildcard DNS record set up.  If you have access to your own zone files, that’s great, otherwise you’ll need to ask your host to set it up for you.  Fair warning though, your hosting company is not stupid (unless it’s Dreamhost) so don’t be surprised if they decline your request.  To set up the DNS zone you simple need to add an a-record “*” like so:

* 14400 IN A 205.134.252.71

*Note: Some argue that you need to use the full  *.domain.com. as the first field…this is actually not required at all, nor recommended!

Depending on your platform, you’ll likely find your domain’s zone file in /var/named/domain.com.db unless you have this feature in your host’s control panel.  Once you’ve added the record simply reload named/BIND with the /etc/init.d/named reload command if needed.   If you’re using an interface it will probably do this for you automatically.

Now you need to add ServerAlias line to your httpd.conf for the wildcard, if your host does not already have Apache configured this way.  Inside the <virtualhost> tags for your domain, add this line:

ServerAlias *.domain.com

Then restart Apache as usual (/etc/init.d/httpd restart) and test a random subdomain to see if it’s working.

So now you will notice that any non-distinguished subdomain shared the same document root as your primary….that’s great and all but it really serves no purpose, so that is where mod_rewrite comes in.  You can add and modify the follow code in your .htaccess to have Apache direct these subdomains to where they need to go:


RewriteEngine On
RewriteRule ^\.htaccess$ – [F]
RewriteCond %{HTTP_HOST} !^www\.example\.com?$
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com?$
RewriteRule ^$ /folder/page.html [L]

Using your imagination you can write your own script that can create subdomains and the appropriate .htaccess entries on-demand (assuming that this is not blocked by mod_security).  The end result is seemingly unlimited subdomains on your account!  Also, the changes are usually immediate and do not require propagation.

Halffinished-468