我正在创建我自己的DNS服务器和主机拦截器,我想从DNS请求消息byte[]
获得主机dns message十六进制转储:
e07901000001000000000000057961686f6f03636f6d0000010001
.y...........yahoo.com.....
代码:
using System;
using System.Text;
public class Program
{
public static void Main()
{
string b64 = "4HkBAAABAAAAAAAABXlhaG9vA2NvbQAAAQAB";
int pad = b64.Length % 4;
if (pad > 0 )
{
b64 += new string('=', 4 - pad);
}
byte[] decoded = Convert.FromBase64String(b64);
int start = 13;
int end = start;
while(decoded[end] != 0){
end++;
}
int hostLength = end-start;
byte[] byteHost = new byte[hostLength];
Array.Copy(decoded, start, byteHost, 0, hostLength);
string host = Encoding.Default.GetString(byteHost);
Console.WriteLine(host); // yahoo♥com
}
}
问题:
- 是我上面的方法获得主机名正确/有效/最快?
- 为什么我得到奇怪的字符取代点
yahoo♥com
?
更改为Encoding。ASCII或编码。UTF8无效
- 不需要第二个数组;
Encoding.GetString
允许您传入偏移量和计数,因此:GetString(decoded, start, hostLength)
-
永远不要使用
Encoding.Default
;这是糟糕的命名-它应该被称为Encoding.Wrong
:)找出什么编码的数据(可能是UTF-8或ASCII),和使用 - 您应该能够使用
IndexOf
找到终止' '
;还要考虑如果没有找到 ,代码应该怎么做。
对于不寻常的字符:数据包含一个03
字节,而您期望.
;检查DNS协议规范,看看这是否是预期的。03
是ETX
(文本结束)。除此之外:我不知道。
找到了答案,03
不是ETX
而是下一个字符串的长度,让我们看看例子
00 05 79 61 68 6F 6F 03 63 6F 6D
. . y a h o o . c o m
05
的平均值为yahoo
的长度,03
为com
的长度
有效的主机或域名只包含44-127或[a-z0-9-.]
的ASCII范围,像bücher.nu
这样的域名将转换为xn--bcher-kva.nu
,所以我用点.
替换像03,0C,09
或44以下的字节
并感谢@Marc Gravell的GetString(decoded, start, hostLength)
/*
I0sBAAABAAAAAAAABmMtcmluZwZtc2VkZ2UDbmV0AAABAAE
ldgBAAABAAAAAAAABWZwLXZwCWF6dXJlZWRnZQNuZXQAAAEAAQ
4HkBAAABAAAAAAAABXlhaG9vA2NvbQAAAQAB
*/
string b64 = "4VoBAAABAAAAAAAAIGYyNWIzNjgyMGUyNDljNGQxY2I0YzQzNGUxNjc5YTljA2Nsbwxmb290cHJpbnRkbnMDY29tAAABAAE";
int pad = b64.Length % 4;
if (pad > 0)
{
b64 += new string ('=', 4 - pad);
}
byte[] decoded = Convert.FromBase64String(b64);
int start = 13;
int end = start;
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
end++;
}
int hostLength = end - start;
string host = Encoding.ASCII.GetString(decoded, start, hostLength);
Console.WriteLine(host);
编辑:微优化,基准测试与1e9或十亿循环
Convert.ToChar()
finished in 00:00:04
for(int i =0; i<1e9; i++){
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
host += Convert.ToChar(decoded[end]);
end++;
}
}
VSEncoding.ASCII.GetString()
跑完全程00:03:20(200秒)
for(int i =0; i<1e9; i++){
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
end++;
}
int hostLength = end - start;
string host = Encoding.ASCII.GetString(decoded, start, hostLength);