1

I'm creating my own DNS server and host blocker, I want to get host from DNS request message byte[]

dns message hex dump:

e07901000001000000000000057961686f6f03636f6d0000010001
.y...........yahoo.com.....

code:

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
    }
}

The questions:

  1. is my method above to get host name right/efficient/fastest ?
  2. why I get weird character replacing the dot yahoo♥com ?

change to Encoding.ASCII or Encoding.UTF8 has no effect

6
  • For reference: it can be interesting to write a DNS server as an academic exercise, but I wouldn't do this for "real things" - just get a pi-hole; it has custom host blocking inbuilt, etc Commented Jan 28, 2021 at 9:11
  • it for learning 😊 Commented Jan 28, 2021 at 9:15
  • Does using this matches your goal and provides the excpected result: new string(decoded.Select(b => (char)b).Where(char.IsLetterOrDigit).ToArray()) ? You can replace IsLetterOrDigit by any logic. Commented Jan 28, 2021 at 11:26
  • @OlivierRogier it will remove the dot. Commented Jan 28, 2021 at 11:54
  • @uingtea Your code outputs yahoo♥com and the snippet àyyahoocom. What do you expect in fact ? yahoo.com ? Commented Jan 28, 2021 at 11:58

2 Answers 2

5
  1. There's no need for the second array; Encoding.GetString allows you to pass in an offset and count, so: GetString(decoded, start, hostLength)
  2. Never use Encoding.Default; that is badly named - it should be called Encoding.Wrong :) Find out what encoding the data is in (probably UTF-8 or ASCII), and use that
  3. You should be able to use IndexOf to find the terminating '\0'; also consider what your code should do if it doesn't find one

As for the unusual character: the data contains an 03 byte where you would expect the .; check the DNS protocol specification to see if this is expected. 03 is ETX (end of text). Beyond that: I don't know.

Sign up to request clarification or add additional context in comments.

2 Comments

thanks, about IndexOf i try Array.IndexOf(decoded, (byte)0); but it return 3 not 18
@uingtea you can provide the start offset too
0

Found the answer, 03 is not ETX but length of the next string, let see the the example

00 05 79 61 68 6F 6F 03 63 6F 6D
.  .  y  a  h  o  o  .  c  o  m

05 mean is the length of yahoo and 03 is for com

Valid host or domain name contains only ASCII range from 44-127 or [a-z0-9-\.], domain like bücher.nu will be converted into xn--bcher-kva.nu, so I replace byte like 03,0C,09 or under 44 with the dot .

and thanks to @Marc Gravell for 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);

edit: micro optimization, benchmark with 1e9 or 1 billion loop

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++;
    }
}

VS Encoding.ASCII.GetString() finished in 00:03:20 (200 seconds)

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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.