Jump to content

php MX Query - differing results


TomT

Recommended Posts

Hi
 
I have an old php4 box that I'm trying to make some use of. I don't have nslookup, php getmxrr etc.
 
I found on the php.net site a function to return the MX records for a domain. In this example I'm using gmail, but I get different results compared to getmxrr().
 
getmxrr shows:
 
Array
(
    [0] => alt1.gmail-smtp-in.l.google.com
    [1] => alt3.gmail-smtp-in.l.google.com
    [2] => alt2.gmail-smtp-in.l.google.com
    [3] => gmail-smtp-in.l.google.com
    [4] => alt4.gmail-smtp-in.l.google.com
)
yet this function returns:

Array
(
    [0] => google.com
    [1] => alt3.google.com
    [2] => alt4.google.com
    [3] => alt2.google.com
    [4] => alt2.google.com.google.com
)
The code below shows how I've called getmxrr and the function, can anyone advise if it's possible to get the results to match getmxrr ?? It's querying the same server on port 53.
 
<?php


getmxrr ( "gmail.com", $mxhosts);


echo "<pre>";
    print_r($mxhosts);
echo "</pre>";




class mxlookup
{
      var $dns_socket = NULL;
      var $QNAME = "";
      var $dns_packet= NULL;
      var $ANCOUNT = 0;
      var $cIx = 0;
      var $dns_repl_domain;
      var $arrMX = array();


      function mxlookup($domain, $dns="8.8.8.8")
      {
         $this->QNAME($domain);
         $this->pack_dns_packet();
         $dns_socket = fsockopen("udp://$dns", 53);


         fwrite($dns_socket,$this->dns_packet,strlen($this->dns_packet));
         $this->dns_reply  = fread($dns_socket,1);


         $bytes = stream_get_meta_data($dns_socket);
         $this->dns_reply .= fread($dns_socket,$bytes['unread_bytes']);
         fclose($dns_socket);
         $this->cIx=6;
         $this->ANCOUNT   = $this->gord(2);
         $this->cIx+=4;
         $this->parse_data($this->dns_repl_domain);
         $this->cIx+=7;


         for($ic=1;$ic<=$this->ANCOUNT;$ic++)
         {
           $QTYPE = ord($this->gdi($this->cIx));
           if($QTYPE!==15){print("[MX Record not returned]"); die();}
           $this->cIx+=9;
           $mxPref = ord($this->gdi($this->cIx));
           $this->parse_data($curmx);
           $this->arrMX[] = $curmx;
           $this->cIx+=3;
         }
      }


      function parse_data(&$retval)
      {
        $arName = array();
        $byte = ord($this->gdi($this->cIx));
        while($byte!==0)
        {
          if($byte==192) //compressed
          {
            $tmpIx = $this->cIx;
            $this->cIx = ord($this->gdi($cIx));
            $tmpName = $retval;
            $this->parse_data($tmpName);
            $retval=$retval.".".$tmpName;
            $this->cIx = $tmpIx+1;
            return;
          }
          $retval="";
          $bCount = $byte;
          for($b=0;$b<$bCount;$b++)
          {
            $retval .= $this->gdi($this->cIx);
          }
          $arName[]=$retval;
         $byte = ord($this->gdi($this->cIx));
       }
       $retval=join(".",$arName);
     }


     function gdi(&$cIx,$bytes=1)
     {
       $this->cIx++;
       return(substr($this->dns_reply, $this->cIx-1, $bytes));
     }


      function QNAME($domain)
      {
        $dot_pos = 0; $temp = "";
        while($dot_pos=strpos($domain,"."))
        {
          $temp   = substr($domain,0,$dot_pos);
          $domain = substr($domain,$dot_pos+1);
          $this->QNAME .= chr(strlen($temp)).$temp;
        }
        $this->QNAME .= chr(strlen($domain)).$domain.chr(0);
      }


      function gord($ln=1)
      {
        $reply="";
        for($i=0;$i<$ln;$i++){
         $reply.=ord(substr($this->dns_reply,$this->cIx,1));
         $this->cIx++;
         }


        return $reply;
      }


      function pack_dns_packet()
      {
        $this->dns_packet = chr(0).chr(1).
                            chr(1).chr(0).
                            chr(0).chr(1).
                            chr(0).chr(0).
                            chr(0).chr(0).
                            chr(0).chr(0).
                            $this->QNAME.
                            chr(0).chr(15).
                            chr(0).chr(1);
      }


}


/* Exampe of use: */
$mx = new mxlookup("gmail.com");


echo "<pre>";
    print_r($mx->arrMX);
echo "</pre>";
?>
adding a var_dump to the gdi function is showing the correct DNS entries, so it's something to do with how the script is joining the results back together.

 function gdi(&$cIx,$bytes=1)
     {
       $this->cIx++;
       var_dump(substr($this->dns_reply, $this->cIx-1, $bytes));
       return(substr($this->dns_reply, $this->cIx-1, $bytes));
     }
 
anyone any ideas ? Thanks

 

Thanks
Link to comment
Share on other sites

Why the heck would someone try to manually write and read DNS UDP packets by hand when there's already a perfectly good function to do it?

Don't bother with that function and just use getmxrr like a sane person.

 

As for the explanation, I don't know. There's a chr(15) in there which could represent an MX query, but my first guess would have been that the query didn't have it.

Link to comment
Share on other sites

Hi.
Thanks for the reply.

I've running this on a very old closed source box running 4.3.10 that doesn't support getmxrr. I can dumb the box but I'd like to try and use it for one task..

 

There is a chr(15) in there with is the MX query.

 

When I added 

 var_dump(substr($this->dns_reply, $this->cIx-1, $bytes));

The output was the correct data as individual strings, it seems to be how this is reassembled is wrong in how it joins the data back up.

I'd be grateful for any help with this.

Thanks

Link to comment
Share on other sites

Short of learning the packet structure, I'd fire up Wireshark (on a modern machine, of course) and run that code to see exactly how the packet is being sent. And compare with what something like nslookup or dig does.

Because it seems to be parsing responses correctly, which means the problem must be in the request.

Link to comment
Share on other sites

And you want to connect that to the Internet? A machine with 12-year-old software that hasn't seen a security update ever since?

He's clearly not going to be surfing porn sites or downloading torrents with it. Sitting behind a proper firewall and without my grandmother using it to download wallpapers of cats, it'll be fine.
Link to comment
Share on other sites

It's only connecting to the internet to send mail, it will be firewalled and port restricted.

I'll try the wireshark option, only issue will be how I decode the resulting packets.

can getmxrr() be enabled in php.ini, or does it need to be compiled in ?

Thanks

Link to comment
Share on other sites

This may be a dumb question, but why not just update PHP? I'm not a server jockey by any stretch, but I don't remember hearing anything about PHP updates that would cause it to not compile on even old equipment. I've got a severely under-powered 7-year old eMachines box sitting in my office that I use as my development LAMP stack and it works wonders for developing and testing. Granted, it's not directly connected to the Internet, and it's not up to version 7 yet, but it does work well.

  • Like 1
Link to comment
Share on other sites

I can dumb the box but I'd like to try and use it for one task..

If one valid course of action is to dump the box and use something else, then there's no reason you can't at least make an effort to upgrade it before using it. Worst case would be you go back to the original plan and dump it.

 

There really shouldn't be any reason you couldn't get a modern OS with updated software on it, or at least a modern PHP version compiled manually. I have some circa 2003 hardware that I was using with FreeNAS and PHP 5.5 for a while just a couple years ago, no problems at all. Currently it's sitting on a shelf doing nothing, but if I ever found a need for it I have no doubts I could just slap a modern Linux OS onto it with current software.

 

Since you mention it being a "closed-source box", I'm going to guess there's a reasonable chance you mean Windows. Even if your using something old like Windows XP you can still update to at least 5.4 by just downloading the appropriate version from windows.php.net

  • Like 1
Link to comment
Share on other sites

Hi

It's Linux based and I've no idea what.

There are no tools on it to compile or make a new version of PHP.
I was hoping to enable getmxrr as that should be supported by PHP4, but I can't see how to do that.

I've just found this, which from the comments sounds like it should work, but it returns nothing for me.

http://stackoverflow.com/questions/24965134/raw-socket-dns-request-in-php#

Any ideas ?

Thanks all help is very much appreciated.

Link to comment
Share on other sites

If it's a Debian flavor of Linux, you should be able to run

sudo apt-get update
sudo apt-get upgrade

and that'll update everything except the operating system itself. Honestly, if you're already thinking about wiping the system and starting over, there's nothing to lose by giving it a shot. And you may end up saving yourself some time and headache.

Link to comment
Share on other sites

Have you tried Net_DNS, as mentioned on the getmxrr manual page?

Unfortunately I don't have the ability to add any new packages to this box.

I'm still think the original script does get the correct data, but is formatting it wrong..  I'll try to find time to day to test this again.

Link to comment
Share on other sites

I presume this is for a personal / hobby based machine and not for a professional endeavour?  Because if you are earning a wage while doing this it would very quickly become more cost effective to just buy a new box and use that than pay you an hourly to muddle through an age old system and create a redundant script just to utilise a near-death piece of hardware.

 

Another option would be to curl a page on a newer server that can do the functions that you need and just manipulate the results provided by that, but then you would have to question why not just use the newer server for the whole process?

Link to comment
Share on other sites

Unfortunately I don't have the ability to add any new packages to this box.

All you have to do is download the files and copy them over. It's not like you need root and the ability to install stuff from a package manager.

If you can make enough changes on the box to edit your script, then you can use Net_DNS.

Link to comment
Share on other sites

Thanks I've copied the Net_DNS files across and it is working..
 

This is the test code I'm using:

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

$resolver = new Net_DNS_Resolver();
$response = $resolver->rawQuery('gmail.com', 'MX');

if ($response) {
  if (count($response->answer)) {
    foreach ($response->answer as $rr) {
      $rr->display();
    }
  }
}
?>

and it returns:

gmail.com. 3524 IN MX 30 alt3.gmail-smtp-in.l.google.com. gmail.com. 3524 IN MX 10 alt1.gmail-smtp-in.l.google.com. gmail.com. 3524 IN MX 40 alt4.gmail-smtp-in.l.google.com. gmail.com. 3524 IN MX 20 alt2.gmail-smtp-in.l.google.com. gmail.com. 3524 IN MX 5 gmail-smtp-in.l.google.com.

Which is all good, How can I change this so it only returns the preference and the address ?
Doing a var_dump on $rr returns :

object(net_dns_rr_mx)( { ["name"]=> string(9) "gmail.com" ["type"]=> string(2) "MX" ["class"]=> string(2) "IN" ["ttl"]=> int(3365) ["rdlength"]=> int(32) ["rdata"]=> string(32) "alt3 gmail-smtp-inlgoogleÀ" ["preference"]=> int(30) ["exchange"]=> string(31) "alt3.gmail-smtp-in.l.google.com" } object(net_dns_rr_mx)( { ["name"]=> string(9) "gmail.com" ["type"]=> string(2) "MX" ["class"]=> string(2) "IN" ["ttl"]=> int(3365) ["rdlength"]=> int(9) ["rdata"]=> string(9) " alt1À." ["preference"]=> int(10) ["exchange"]=> string(31) "alt1.gmail-smtp-in.l.google.com" } object(net_dns_rr_mx)( { ["name"]=> string(9) "gmail.com" ["type"]=> string(2) "MX" ["class"]=> string(2) "IN" ["ttl"]=> int(3365) ["rdlength"]=> int(9) ["rdata"]=> string(9) "(alt4À." ["preference"]=> int(40) ["exchange"]=> string(31) "alt4.gmail-smtp-in.l.google.com" } object(net_dns_rr_mx)( { ["name"]=> string(9) "gmail.com" ["type"]=> string(2) "MX" ["class"]=> string(2) "IN" ["ttl"]=> int(3365) ["rdlength"]=> int(9) ["rdata"]=> string(9) "alt2À." ["preference"]=> int(20) ["exchange"]=> string(31) "alt2.gmail-smtp-in.l.google.com" } object(net_dns_rr_mx)( { ["name"]=> string(9) "gmail.com" ["type"]=> string(2) "MX" ["class"]=> string(2) "IN" ["ttl"]=> int(3365) ["rdlength"]=> int(4) ["rdata"]=> string(4) "À." ["preference"]=> int(5) ["exchange"]=> string(26) "gmail-smtp-in.l.google.com" }

I've tried to echo $rr['answer']['preference'] and $rr['preference']but that doesn't return anything.

Thank again for all your help :)

 

Link to comment
Share on other sites

Thanks this is now working and returning the results correctly :D
 

Array
(
[5] => gmail-smtp-in.l.google.com
[10] => alt1.gmail-smtp-in.l.google.com
[20] => alt2.gmail-smtp-in.l.google.com
[30] => alt3.gmail-smtp-in.l.google.com
[40] => alt4.gmail-smtp-in.l.google.com
)

Thanks much appreciated.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.