<?php
$domain = 'www.google.com';
$dns = '8.8.8.8';
$timeout = 2;
$data = rand(10, 77) . "\0\0\0\0\1\0\0\0\0\0";
$data .= pack('n', '1') . pack('n', '0') . pack('n', '0') . pack('n', '0');
foreach (explode('.', $domain) as $bit) {
$l = strlen($bit);
$data .= chr($l) . $bit;
}
$data .= "\0\0" . pack('n', '2') . pack('n', '1');
$errno = $errstr = 0;
$fp = fsockopen('udp://' . $dns, 53, $errno, $errstr, $timeout);
if (!$fp || !is_resource($fp)) return $errno;
socket_set_timeout($fp, $timeout);
fwrite($fp, $data);
var_dump ( fread($fp, 8192) );
fclose($fp);
这是我一直试图开始工作的代码。以下是dns查找http://www.binarytides.com/dns-query-code-in-c-with-linux-sockets/的C实现的片段。我无法看到我在PHP中错过了什么。
至于使用dns_get_records,它可以工作,但它没有超时,这对我来说非常糟糕,因为我将要处理许多查找/秒。这是我的解决方案$lookup = shell_exec('dig "' . $cleaned_host . '." -t ANY +nomultiline +nocomments +nonssearch +tcp +nostats +qr +time=1');
,但即使有了这样的改进,性能也是dns_get_records速度的两倍以上,这对我的情况非常不利。因此,我尝试使用DNS服务器进行原始套接字连接,假设速度将是dns_get_records的速度。
另一种方法是通过ini_set限制dns_get_records函数,例如default_socket_timeout,但我找不到任何可以使用的函数。
更好的解决方案(可以与脚本的其余部分一起使用)是获取cURL dns缓存。
答案 0 :(得分:1)
大多数情况下,您未能发现的是C代码使用九个单独的位域将DNS标头标记打包成一个单独的16位字段,而您尝试追加9单独的字节。
您应该在随机查询ID之后添加pack('n', 0x0100)
,以便设置RD
(所需的递归)位。
此外,您只应在域名后添加一个\0
,以表示尾随的“根”标签,或者确保您提供的每个域名都有一个尾随点,以便{{1这个功能对你有用。此代码有效:
explode
不要忘记参考RFC 1035来了解如何正确解码响应!
答案 1 :(得分:1)
我需要一个代码来检查某个DNS服务器是否将DNS委托给另一台服务器,我已经从上面的示例开始,我的最终代码是:
function has_ns_records( $domain, $dns = 'dns1.nic.blog' ) {
$timeout = 2;
// Create a question packet
$data = pack( 'n6', rand(10, 77), 0x0100, 1, 0, 0, 0 );
foreach ( explode('.', $domain ) as $part ) {
$length = strlen( $part );
$data .= chr( $length ) . $part;
}
$data .= pack( 'n2' , 2, 1 ); // QTYPE=NS, QCLASS=IN
$errno = $errstr = 0;
$fp = fsockopen( 'udp://' . $dns, 53, $errno, $errstr, $timeout );
if (!$fp || !is_resource($fp)) return $errno;
socket_set_timeout( $fp, $timeout );
fwrite( $fp, $data );
$response_data = fread( $fp, 8192 );
fclose( $fp );
// read answer header
$ans_header = unpack( "nid/nspec/nqdcount/nancount/nnscount/narcount", substr( $response_data, 0, 12 ) );
// skip question part
$offset = strlen( $domain ) + 4 + 2 + 1; // 4 => QTYPE + QCLASS, 2 => len, 1 => null terminator
$record_header = unpack("ntype/nclass/Nttl/nlength", substr( $response_data, 12 + $offset, 10 ) );
// Expect type NS and class IN, when domain not exist it returns SOA (6)
return $record_header[ 'type' ] === 2 && $record_header[ 'class' ] === 1;
}
var_dump( has_ns_records( 'get.blog.' ) );