protected TMessage SendMessage <TMessage>(TMessage message) where TMessage : DnsMessageBase, new() { int messageLength; byte[] messageData; DnsServer.SelectTsigKey tsigKeySelector; byte[] tsigOriginalMac; PrepareMessage(message, out messageLength, out messageData, out tsigKeySelector, out tsigOriginalMac); bool sendByTcp = ((messageLength > MaximumQueryMessageSize) || message.IsTcpUsingRequested || !IsUdpEnabled); var endpointInfos = GetEndpointInfos(); for (int i = 0; i < endpointInfos.Count; i++) { var endpointInfo = endpointInfos[i]; TcpClient tcpClient = null; System.IO.Stream tcpStream = null; string reusableMapKey = string.Concat(endpointInfo.ServerAddress, endpointInfo.ServerPort); if (sendByTcp && this.IsReuseTcpEnabled) { if (!this.reusableTcp.ContainsKey(reusableMapKey)) { this.reusableTcp[reusableMapKey] = new ReusableTcpConnection(); } ReusableTcpConnection reuse = this.reusableTcp[reusableMapKey]; tcpClient = reuse.Client; tcpStream = reuse.Stream; this.reusableTcp[reusableMapKey].LastUsed = DateTime.UtcNow; } try { IPAddress responderAddress; int responderPort = 0; byte[] resultData = sendByTcp ? QueryByTcp(endpointInfo.ServerAddress, endpointInfo.ServerPort, messageData, messageLength, ref tcpClient, ref tcpStream, out responderAddress, out responderPort) : QueryByUdp(endpointInfo, messageData, messageLength, out responderAddress); if (resultData != null) { TMessage result; try { result = DnsMessageBase.Parse <TMessage>(resultData, tsigKeySelector, tsigOriginalMac); } catch (Exception e) { Trace.TraceError("Error on dns query: " + e); continue; } if (!ValidateResponse(message, result)) { continue; } if ((result.ReturnCode == ReturnCode.ServerFailure) && (i != endpointInfos.Count - 1)) { continue; } if (result.IsTcpResendingRequested) { resultData = QueryByTcp(responderAddress, responderPort, messageData, messageLength, ref tcpClient, ref tcpStream, out responderAddress, out responderPort); if (resultData != null) { TMessage tcpResult; try { tcpResult = DnsMessageBase.Parse <TMessage>(resultData, tsigKeySelector, tsigOriginalMac); } catch (Exception e) { Trace.TraceError("Error on dns query: " + e); continue; } if (tcpResult.ReturnCode == ReturnCode.ServerFailure) { if (i != endpointInfos.Count - 1) { continue; } } else { result = tcpResult; } } } bool isTcpNextMessageWaiting = result.IsTcpNextMessageWaiting(false); bool isSucessfullFinished = true; while (isTcpNextMessageWaiting) { resultData = QueryByTcp(responderAddress, responderPort, null, 0, ref tcpClient, ref tcpStream, out responderAddress, out responderPort); if (resultData != null) { TMessage tcpResult; try { tcpResult = DnsMessageBase.Parse <TMessage>(resultData, tsigKeySelector, tsigOriginalMac); } catch (Exception e) { Trace.TraceError("Error on dns query: " + e); isSucessfullFinished = false; break; } if (tcpResult.ReturnCode == ReturnCode.ServerFailure) { isSucessfullFinished = false; break; } else { result.AnswerRecords.AddRange(tcpResult.AnswerRecords); isTcpNextMessageWaiting = tcpResult.IsTcpNextMessageWaiting(true); } } else { isSucessfullFinished = false; break; } } if (isSucessfullFinished) { return(result); } } } finally { try { if (sendByTcp && this.IsReuseTcpEnabled) { if (this.reusableTcp[reusableMapKey].Client == null || !ReferenceEquals(this.reusableTcp[reusableMapKey].Client, tcpClient)) { this.reusableTcp[reusableMapKey].Client = tcpClient; this.reusableTcp[reusableMapKey].Stream = tcpStream; } } else { tcpStream?.Dispose(); tcpClient?.Close(); } } catch { // ignored } } } return(null); }
protected virtual async Task <QueryResponse> QueryByTcpAsync(IPAddress nameServer, int port, byte[] messageData, int messageLength, TcpClient tcpClient, System.IO.Stream tcpStream, CancellationToken token) { if (!IsTcpEnabled) { return(null); } string reusableMapKey = string.Concat(nameServer, port); if (tcpClient == null && this.IsReuseTcpEnabled) { if (!this.reusableTcp.ContainsKey(reusableMapKey)) { this.reusableTcp[reusableMapKey] = new ReusableTcpConnection(); } ReusableTcpConnection reuse = this.reusableTcp[reusableMapKey]; tcpClient = reuse.Client; tcpStream = reuse.Stream; this.reusableTcp[reusableMapKey].LastUsed = DateTime.UtcNow; } int responderPort = port == 0 ? _port : port; try { if (tcpClient == null || (this.IsReuseTcpEnabled && !tcpClient.IsConnected())) { tcpClient = new TcpClient(nameServer.AddressFamily) { ReceiveTimeout = QueryTimeout, SendTimeout = QueryTimeout }; if (!await tcpClient.TryConnectAsync(nameServer, responderPort, QueryTimeout, token)) { if (this.IsReuseTcpEnabled) { try { tcpClient.Close(); } catch (Exception) { } } return(null); } tcpStream = tcpClient.GetStream(); } int tmp = 0; byte[] lengthBuffer = new byte[2]; if (messageLength > 0) { DnsMessageBase.EncodeUShort(lengthBuffer, ref tmp, (ushort)messageLength); await tcpStream.WriteAsync(lengthBuffer, 0, 2, token); await tcpStream.WriteAsync(messageData, 0, messageLength, token); } if (!await TryReadAsync(tcpClient, tcpStream, lengthBuffer, 2, token)) { return(null); } tmp = 0; int length = DnsMessageBase.ParseUShort(lengthBuffer, ref tmp); byte[] resultData = new byte[length]; return(await TryReadAsync(tcpClient, tcpStream, resultData, length, token) ? new QueryResponse(resultData, nameServer, tcpClient, tcpStream, responderPort) : null); } catch (Exception e) { Trace.TraceError("Error on dns query: " + e); return(null); } }
protected async override Task <QueryResponse> QueryByTcpAsync(IPAddress nameServer, int port, byte[] messageData, int messageLength, TcpClient tcpClient, System.IO.Stream tlsStream, CancellationToken token) { if (!IsTcpEnabled) { return(null); } int responderPort = port == 0 ? _port : port; TlsUpstreamServer tlsServer = _tlsservers.Where(t => t.IPAddress == nameServer && t.Port == responderPort).FirstOrDefault(); if (tlsServer == null) { Trace.TraceError("Error on dns query: invalid TLS upstream server"); return(null); } string reusableMapKey = string.Concat(nameServer, port); if (tcpClient == null && this.IsReuseTcpEnabled) { if (!this.reusableTcp.ContainsKey(reusableMapKey)) { this.reusableTcp[reusableMapKey] = new ReusableTcpConnection(); } ReusableTcpConnection reuse = this.reusableTcp[reusableMapKey]; tcpClient = reuse.Client; tlsStream = reuse.Stream; this.reusableTcp[reusableMapKey].LastUsed = DateTime.UtcNow; } try { if (tcpClient == null || (this.IsReuseTcpEnabled && !tcpClient.IsConnected())) { tcpClient = new TcpClient(nameServer.AddressFamily) { ReceiveTimeout = QueryTimeout, SendTimeout = QueryTimeout }; if (!await tcpClient.TryConnectAsync(nameServer, responderPort, QueryTimeout, token)) { return(null); } SslStream sslStream = new SslStream(tcpClient.GetStream(), true, new RemoteCertificateValidationCallback(tlsServer.ValidateRemoteCertificate)); tlsStream = sslStream; try { sslStream.AuthenticateAsClient(tlsServer.AuthName ?? string.Empty, new X509CertificateCollection(), tlsServer.SslProtocols, false); } catch (Exception) { } if (!sslStream.IsAuthenticated) { Trace.TraceError("Error on dns query: invalid TLS upstream server certificate"); if (this.IsReuseTcpEnabled) { try { tlsStream.Dispose(); tcpClient.Close(); } catch (Exception) { } } return(null); } } int tmp = 0; byte[] lengthBuffer = new byte[2]; if (messageLength > 0) { DnsMessageBase.EncodeUShort(lengthBuffer, ref tmp, (ushort)messageLength); await tlsStream.WriteAsync(lengthBuffer, 0, 2, token); await tlsStream.WriteAsync(messageData, 0, messageLength, token); } if (!await TryReadAsync(tcpClient, tlsStream, lengthBuffer, 2, token)) { return(null); } tmp = 0; int length = DnsMessageBase.ParseUShort(lengthBuffer, ref tmp); byte[] resultData = new byte[length]; return(await TryReadAsync(tcpClient, tlsStream, resultData, length, token) ? new QueryResponse(resultData, nameServer, tcpClient, tlsStream, responderPort) : null); } catch (Exception e) { Trace.TraceError("Error on dns query: " + e); return(null); } }