@
Puteulanus #6 不错的示范 😄
于是我照猫画虎,经过约 5 轮的对话,免费的 GPT 3.5 为我写了个能 work 的 PHP 版本:
```
<?php
// 指定域名
$targetDomain = '
somename.com';
// 响应 IP 地址
$responseIP = '1.2.4.8';
// 启动 DNS 服务器
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, '127.0.0.1', 5345);
echo "DNS 服务器已启动...\n";
while (true) {
socket_recvfrom($socket, $data, 512, 0, $from, $port);
// 解析 DNS 请求
$dnsRequest = dns_parse_message($data);
// 打印收到的 DNS 请求
echo "收到 DNS 请求:\n";
print_r($dnsRequest);
// 检查请求是否为 A 记录且为目标域名的子域名
if ($dnsRequest && isset($dnsRequest['question'][0]['qtype']) && $dnsRequest['question'][0]['qtype'] == 0 && endsWith($dnsRequest['question'][0]['qname'], ".$targetDomain")) {
// 构建响应数据
$dnsResponse = dns_build_response($dnsRequest, $responseIP);
// 打印响应数据
echo "准备发送的 DNS 响应:\n";
print_r($dnsResponse);
// 发送响应
$bytesSent = socket_sendto($socket, $dnsResponse, strlen($dnsResponse), 0, $from, $port);
if ($bytesSent === false) {
echo "发送 DNS 响应失败\n";
} else {
echo "已发送 $bytesSent 字节的 DNS 响应\n";
}
echo "已响应 DNS 请求:{$dnsRequest['question'][0]['qname']} -> $responseIP\n";
}
}
// 解析 DNS 请求
function dns_parse_message($data)
{
$dnsHeader = unpack('nid/nflags/nqdcount/nancount/nnscount/narcount', substr($data, 0, 12));
$question = [];
$offset = 12;
for ($i = 0; $i < $dnsHeader['qdcount']; $i++) {
$questionName = '';
$nameFound = false;
while (true) {
$labelLength = ord($data[$offset]);
if ($labelLength == 0) {
$offset++;
break;
}
if (($labelLength & 0xC0) == 0xC0) {
$offset += 2; // 跳过指针
break;
}
$questionName .= substr($data, $offset + 1, $labelLength) . '.';
$offset += $labelLength + 1;
}
$offset += 4;
$question[] = [
'qname' => rtrim($questionName, '.'),
'qtype' => isset(unpack('ntype', substr($data, $offset, 2))['type']) ? unpack('ntype', substr($data, $offset, 2))['type'] : '',
];
$offset += 4;
}
return [
'header' => $dnsHeader,
'question' => $question,
];
}
// 构建 DNS 响应
function dns_build_response($request, $ip)
{
$header = pack('nnnnnn', $request['header']['id'], 0x8180, 1, 1, 0, 0);
$question = '';
foreach ($request['question'] as $q) {
$question .= dns_compress_name($q['qname']) . pack('nn', 1, 1);
}
$answer = dns_compress_name($request['question'][0]['qname']) . pack('n*', 1, 1, 0, 1, 0, 4); // 响应类型为 A 记录,TTL 为 0 ,数据长度为 4
$answer .= inet_pton($ip); // 将 IP 地址转换为二进制格式
return $header . $question . $answer;
}
// 辅助函数,检查字符串结尾
function endsWith($haystack, $needle)
{
return substr($haystack, -strlen($needle)) === $needle;
}
// 辅助函数,压缩 DNS 消息中的域名
function dns_compress_name($name)
{
$parts = explode('.', $name);
$compressedName = '';
foreach ($parts as $part) {
$compressedName .= chr(strlen($part)) . $part;
}
return $compressedName . "\x00";
}
?>
```