Does your stack support DNS SRV?

Feb 18, 2010 at 9:39 PM

TIA

Regards

Feb 18, 2010 at 9:52 PM

Question withdrawn. Answer is obviously yes :)

Regards

 

Feb 18, 2010 at 10:01 PM

... but just for UDP. What is the plan concering TCP? I have removed the exception, and it seems to work well. What's the problem?

Coordinator
Feb 18, 2010 at 11:24 PM

Really? It's been a little bit since I looked at that, but I recall running into some issues....it might have been with larger responses...

let me know how it fairs!

thanks.

later,
jason

Feb 19, 2010 at 6:06 AM

No, I was wrong. I thought it would work with TCP, but it doesn't. But I didn't want to place yet another message last night :)

 

Coordinator
Feb 19, 2010 at 2:09 PM

Ah, okay ... it's behaving how I recall.  If you want to take a stab at it, go for it. It may be a little bit before I get to it, but I do plan to.

Coordinator
Feb 19, 2010 at 2:42 PM
I went and checked the RFC on DNS over TCP and ran across this one difference. Perhaps this is all it will take?

From RFC 1035:

4.2.2. TCP usage

Messages sent over TCP connections use server port 53 (decimal). The message is prefixed with a two byte length field which gives the message length, excluding the two byte length field. This length field allows
the low-level processing to assemble a complete message before beginning to parse it.
Feb 19, 2010 at 3:21 PM

Thanks for the input. I'll give that a try, definitely. I'm working on a RELOAD stack http://tools.ietf.org/html/draft-ietf-p2psip-base-07

The current spec states in 10.2:
 

If a URL for the enrollment server is not
provided, the node MUST do a DNS SRV query using a Service name of
"p2psip_enroll" and a protocol of tcp to find an enrollment server
and form the URL by appending a path of "/p2psip/ enroll" to the
overlay name. For example, if the overlay name was example.com, the
URL would be "https://example.com/p2psip/enroll".

I don't know, why the insist to have TCP as protocol, but they do.

 

 

 

Feb 19, 2010 at 3:21 PM

Would be great to know  a DNS server, which supports TCP. Mine doesn't :)

 

Coordinator
Feb 19, 2010 at 4:40 PM

I read through the P2PSIP spec and it doesn't specify TCP or UDP for the DNS SRV record resolution, meaning UDP should be fine. Do you just prefer doing TCP instead, or are you hoping to do both and have it configurable.

Also, try using the DNS servers from OpenDNS:
http://www.opendns.com/

208.67.222.222
208.67.220.220

I bet they support TCP queries, they actually offer great free DNS services as well.

Feb 19, 2010 at 5:35 PM

Hmm. Thanks for the addresses. 

I read this part as indication for mandatory TCP, don't you?

If a URL for the enrollment server is not
provided, the node MUST do a DNS SRV query using a Service name of
"p2psip_enroll" and a protocol of tcp to find an enrollment server
and form the URL by appending a path of "/p2psip/ enroll" to the
overlay name. For example, if the overlay name was example.com, the
URL would be "https://example.com/p2psip/enroll".

If it doesn't mean, what I thought, then I'm fine with UDP.
Regards


        
    
Coordinator
Feb 19, 2010 at 5:38 PM

lol, apparently I'm blind -  read through it 3 times. I think that means what you think it means. Not sure why they insist on TCP as UDP might work anyway - but the RFC is the RFC, probably best to follow it as best you can.

Feb 19, 2010 at 5:38 PM

Probably you might consider to add an overload for the resolve function, which derives the DNS addresses from the system. Here is the code to gather DNS servers:

 

            IPGlobalProperties computerProperties = IPGlobalProperties.GetIPGlobalProperties();
            NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
            string device_id = "";
            /* device_id is derived from the first Ethernet or WiFi device in state UP found locally */
            foreach (NetworkInterface adapter in nics) {
                if (adapter.OperationalStatus == OperationalStatus.Up &&
                    (adapter.NetworkInterfaceType == NetworkInterfaceType.Ethernet ||
                    adapter.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)) {
                    device_id = adapter.GetPhysicalAddress().ToString();
                    IPInterfaceProperties props = adapter.GetIPProperties();
                    foreach (IPAddress address in props.DnsAddresses) {
                        DnsQueryRequest dnsQuery = new DnsQueryRequest();
                        DnsQueryResponse dnsResponse = dnsQuery.Resolve(address.ToString(), "imap.freenet.de", DnDns.Enums.NsType.SRV, DnDns.Enums.NsClass.INET, System.Net.Sockets.ProtocolType.Udp);
                        foreach (IDnsRecord record in dnsResponse.Answers) {
                            Console.WriteLine(record.Answer);
                        }
                    }
                }
            }

using System.Net.NetworkInformation;

            IPGlobalProperties computerProperties = IPGlobalProperties.GetIPGlobalProperties();

            NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();

            foreach (NetworkInterface adapter in nics) {

                if (adapter.OperationalStatus == OperationalStatus.Up &&

                    (adapter.NetworkInterfaceType == NetworkInterfaceType.Ethernet ||

                    adapter.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)) {

                    IPInterfaceProperties props = adapter.GetIPProperties();

                    foreach (IPAddress address in props.DnsAddresses) {

.....

                    }

                }

            }

 

Feb 19, 2010 at 5:59 PM

Good guess with RFC 1035. In a quick shot I've modified the code this way (red part - my mods). It will be better to apply the necessary changes to the encoder/decoder, but this code works fine. It enlarges the message buffer by 2 and stuffs the length. Then it handles the returned buffer  accordingly.

 

                        TcpClient tcpClient = new TcpClient();
                        try
                        {
                            tcpClient.Connect(ipep);
                            NetworkStream netStream = tcpClient.GetStream();
                            BinaryReader netReader = new System.IO.BinaryReader(netStream);
                            //netStream.CanWrite)
                            int len = bDnsQuery.Length;
                            Array.Resize<byte>(ref bDnsQuery, len + 2);
                            Array.Copy(bDnsQuery, 0, bDnsQuery, 2, len);
                            bDnsQuery[0] = (byte)((len >> 8) & 0xFF);
                            bDnsQuery[1] = (byte)((len & 0xFF));
                            netStream.Write(bDnsQuery, 0, bDnsQuery.Length);
                            
                            while (!netStream.DataAvailable) ;
                            if (tcpClient.Connected && netStream.DataAvailable)
                            {
                                MemoryStream memStream = new MemoryStream(1024);
                                bool canRead = netStream.DataAvailable;
                                
                                while (canRead)
                                {
                                    int byteRead = netStream.ReadByte();
                                    byte[] result = BitConverter.GetBytes(byteRead);
                                    memStream.WriteByte(result[0]);
                                    canRead = netStream.DataAvailable;
                                }
                                recvBytes = memStream.GetBuffer();
                                Array.Copy(recvBytes, 2, recvBytes, 0, recvBytes.Length - 2);
                            }
                        }
                        finally
                        {
                            tcpClient.Close();
                        }

                        TcpClient tcpClient = new TcpClient();

 

                        try

                        {

                            tcpClient.Connect(ipep);

 

                            NetworkStream netStream = tcpClient.GetStream();

                            BinaryReader netReader = new System.IO.BinaryReader(netStream);

                            //netStream.CanWrite)

                            int len = bDnsQuery.Length;

                            Array.Resize<byte>(ref bDnsQuery, len + 2);

                            Array.Copy(bDnsQuery, 0, bDnsQuery, 2, len);

                            bDnsQuery[0] = (byte)((len >> 8) & 0xFF);

                            bDnsQuery[1] = (byte)((len & 0xFF));

                            netStream.Write(bDnsQuery, 0, bDnsQuery.Length);

 

                            while (!netStream.DataAvailable) ;

 

                            if (tcpClient.Connected && netStream.DataAvailable)

                            {

                                MemoryStream memStream = new MemoryStream(1024);

                                bool canRead = netStream.DataAvailable;

 

                                while (canRead)

                                {

                                    int byteRead = netStream.ReadByte();

                                    byte[] result = BitConverter.GetBytes(byteRead);

 

                                    memStream.WriteByte(result[0]);

                                    canRead = netStream.DataAvailable;

                                }

                                recvBytes = memStream.GetBuffer();

                                Array.Copy(recvBytes, 2, recvBytes, 0, recvBytes.Length - 2);

                            }

                        }

                        finally

                        {

                            tcpClient.Close();

                        }

 

 

Feb 19, 2010 at 6:01 PM

Good job at all, btw. Nice and clear code, simple usage, great benefit :)

 

Coordinator
Feb 19, 2010 at 6:24 PM

Thanks! Excellent - thanks for the code changes. I'll add that to the library.

Feb 19, 2010 at 7:19 PM

I think I was wrong with my TCP assumption on RELOAD. Reading the draft again, I think I have to look up this using DNS SRV:

_p2psip_enroll._tcp.example.com

What do you think?

Coordinator
Feb 19, 2010 at 7:49 PM
Edited Feb 19, 2010 at 7:58 PM

Ahh! That makes a lot more sense.

See section 2.2 of P2PSIP bootstrapping using DNS-SD referenced in section 10.2 of the RFC:
http://tools.ietf.org/html/draft-garcia-p2psip-dns-sd-bootstrapping-00#section-2

The <Service> portion of the Service Instance Name consists of a pair
of DNS labels following the established convention for SRV records
[RFC2782], namely: the first label of the pair is the Application
Protocol Name, and the second label is either "_tcp" or "_udp",
depending on the transport protocol used by the application.

Feb 19, 2010 at 7:59 PM

Cool. Best find this evening :) That's it and it explains it all. I already had not a good feeling with my DNS over TCP assumption, because this was a bit unlikely... However, we've made it run either, so it wasn't wasted time at all.

Have a nice weekend.

Regards

 

Coordinator
Feb 19, 2010 at 8:04 PM

One other thing: did you pull the latest from the source repository or did you download the source code distribution package?  There are some bugs in the Dist package that have been fixed in the source repository.

Coordinator
Feb 19, 2010 at 8:05 PM

You too! Thanks again.

Feb 19, 2010 at 8:19 PM

Hmm. Think I got the distribution package. Where and how to get the latest?

Regards

 

Coordinator
Feb 19, 2010 at 8:27 PM

Np. Go to the Source Code tab and on the right hand side you'll see a link that says "Download" - that will get you changeset 19629.

Feb 19, 2010 at 8:45 PM

Got it. Do you plan to integrate the TCP support the next days?

Regards

 

Coordinator
Feb 19, 2010 at 8:57 PM

I'm hoping I may have some time to put it in this weekend and build a new release package since most people don't download from the latest changeset.

Feb 19, 2010 at 9:03 PM

Take your time. It doesn't hurry anymore to me :)

Regards

 

Feb 24, 2010 at 3:34 PM

 

        public static IPAddressCollection DiscoverDnsServerAddresses()
        {
            NetworkInterface[] arrNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
            foreach (NetworkInterface objNetworkInterface in arrNetworkInterfaces)
            {
                if (
                    (objNetworkInterface.OperationalStatus == OperationalStatus.Up) &&
                    (objNetworkInterface.Speed > 0) && 
                    (objNetworkInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback)&& 
                    (objNetworkInterface.NetworkInterfaceType != NetworkInterfaceType.Tunnel)
                    )
                {
                    IPAddressCollection candidate = objNetworkInterface.GetIPProperties().DnsAddresses;
                    bool found = false;
                    foreach (IPAddress addr in candidate) {
                        if (addr.AddressFamily == AddressFamily.InterNetwork)
                            found = true;
                    }
                    if (found)
                        return candidate;
                }
            }
            return null;
        }

Hi,

I would suggest you to change DiscoverDnsServerAddresses in Tools.cs accordingly. Otherwise there is a chance to return IPV6 addresses, which doesn't relly work right now :)

 

        public static IPAddressCollection DiscoverDnsServerAddresses()

        {

            NetworkInterface[] arrNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();

            foreach (NetworkInterface objNetworkInterface in arrNetworkInterfaces)

            {

                if (

                    (objNetworkInterface.OperationalStatus == OperationalStatus.Up) &&

                    (objNetworkInterface.Speed > 0) && 

                    (objNetworkInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback)&& 

                    (objNetworkInterface.NetworkInterfaceType != NetworkInterfaceType.Tunnel)

                    )

                {

                    IPAddressCollection candidate = objNetworkInterface.GetIPProperties().DnsAddresses;

                    bool found = false;

                    foreach (IPAddress addr in candidate) {

                        if (addr.AddressFamily == AddressFamily.InterNetwork)

                            found = true;

                    }

                    if (found)

                        return candidate;

                }

            }

            return null;

        }

 

Coordinator
Feb 25, 2010 at 6:55 PM

Ahh, great point. Will do.

Coordinator
Feb 26, 2010 at 1:31 PM

Change has been checked in.