public DnsDatagram Resolve(DnsDatagram request) { int bytesRecv; byte[] responseBuffer = null; int nextServerIndex = 0; int retries = _retries; byte[] requestBuffer; IDnsCache dnsCache = null; //serialize request using (MemoryStream mS = new MemoryStream(32)) { if (_tcp) { mS.Position = 2; } //write dns datagram request.WriteTo(mS); requestBuffer = mS.ToArray(); if (_tcp) { byte[] length = BitConverter.GetBytes(Convert.ToUInt16(requestBuffer.Length - 2)); requestBuffer[0] = length[1]; requestBuffer[1] = length[0]; } } //init server selection parameters if (_servers.Length > 1) { retries = retries * _servers.Length; //retries on per server basis byte[] select = new byte[1]; _rnd.GetBytes(select); nextServerIndex = select[0] % _servers.Length; } int retry = 0; while (retry < retries) { //select server NameServerAddress server; if (_servers.Length > 1) { server = _servers[nextServerIndex]; nextServerIndex = (nextServerIndex + 1) % _servers.Length; } else { server = _servers[0]; } if (server.EndPoint == null) { if (dnsCache == null) { dnsCache = new SimpleDnsCache(); } server.ResolveAddress(dnsCache, _proxy, _preferIPv6, _tcp, _retries); if (server.EndPoint == null) { retry++; continue; } } //query server Socket _socket = null; SocksUdpAssociateRequestHandler proxyRequestHandler = null; try { retry++; DateTime sentAt = DateTime.UtcNow; bool dnsTcp; if (_proxy == null) { if (_tcp) { _socket = new Socket(server.EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _socket.NoDelay = true; _socket.SendTimeout = _sendTimeout; _socket.ReceiveTimeout = _recvTimeout; IAsyncResult result = _socket.BeginConnect(server.EndPoint, null, null); if (!result.AsyncWaitHandle.WaitOne(_connectionTimeout)) { throw new SocketException((int)SocketError.TimedOut); } if (!_socket.Connected) { throw new SocketException((int)SocketError.ConnectionRefused); } } else { _socket = new Socket(server.EndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); _socket.SendTimeout = _sendTimeout; _socket.ReceiveTimeout = _recvTimeout; } dnsTcp = _tcp; } else { switch (_proxy.Type) { case NetProxyType.Http: _socket = _proxy.HttpProxy.Connect(server.EndPoint, _connectionTimeout); _socket.NoDelay = true; _socket.SendTimeout = _sendTimeout; _socket.ReceiveTimeout = _recvTimeout; dnsTcp = true; break; case NetProxyType.Socks5: if (!_tcp) { try { proxyRequestHandler = _proxy.SocksProxy.UdpAssociate(_connectionTimeout); proxyRequestHandler.ReceiveTimeout = _recvTimeout; dnsTcp = false; break; } catch (SocksClientException) { } } using (SocksConnectRequestHandler requestHandler = _proxy.SocksProxy.Connect(server.EndPoint, _connectionTimeout)) { _socket = requestHandler.GetSocket(); _socket.NoDelay = true; _socket.SendTimeout = _sendTimeout; _socket.ReceiveTimeout = _recvTimeout; dnsTcp = true; } break; default: throw new NotSupportedException("Proxy type not supported by DnsClient."); } } if (dnsTcp) { _socket.Send(requestBuffer); if ((responseBuffer == null) || (responseBuffer.Length == 512)) { responseBuffer = new byte[64 * 1024]; } bytesRecv = _socket.Receive(responseBuffer, 0, 2, SocketFlags.None); if (bytesRecv < 1) { throw new SocketException((int)SocketError.ConnectionReset); } Array.Reverse(responseBuffer, 0, 2); ushort length = BitConverter.ToUInt16(responseBuffer, 0); int offset = 0; while (offset < length) { bytesRecv = _socket.Receive(responseBuffer, offset, length, SocketFlags.None); if (bytesRecv < 1) { throw new SocketException((int)SocketError.ConnectionReset); } offset += bytesRecv; } bytesRecv = length; } else { if (responseBuffer == null) { responseBuffer = new byte[512]; } if (proxyRequestHandler == null) { _socket.SendTo(requestBuffer, server.EndPoint); EndPoint remoteEP; if (server.EndPoint.AddressFamily == AddressFamily.InterNetworkV6) { remoteEP = new IPEndPoint(IPAddress.IPv6Any, 0); } else { remoteEP = new IPEndPoint(IPAddress.Any, 0); } bytesRecv = _socket.ReceiveFrom(responseBuffer, ref remoteEP); } else { proxyRequestHandler.SendTo(requestBuffer, 0, requestBuffer.Length, new SocksEndPoint(server.EndPoint)); bytesRecv = proxyRequestHandler.ReceiveFrom(responseBuffer, 0, responseBuffer.Length, out SocksEndPoint socksRemoteEP); } } //parse response using (MemoryStream mS = new MemoryStream(responseBuffer, 0, bytesRecv, false)) { double rtt = (DateTime.UtcNow - sentAt).TotalMilliseconds; DnsDatagram response = new DnsDatagram(mS, server, (_tcp ? ProtocolType.Tcp : ProtocolType.Udp), rtt); if (response.Header.Identifier == request.Header.Identifier) { return(response); } } } catch (SocketException) { } finally { if (_socket != null) { _socket.Dispose(); } if (proxyRequestHandler != null) { proxyRequestHandler.Dispose(); } } } throw new DnsClientException("DnsClient failed to resolve the request: no response from name servers."); }