区分不同类型的 EIdDnsResolverError

Distinguish EIdDnsResolverError of different kind

我正在使用 TIdDNSResolver 扫描本地网络中的 DNS 服务器,因此 DNS 请求的结果并不重要。我检查是否有 DNS 服务器。

该应用也不应依赖于所请求的 DNS 记录是否存在,因此它请求的不是现有主机,而是明知不存在的名称。

在这种情况下,引发了 EIdDnsResolverError 类型的异常。

此异常可能伴随以下错误文本:

我不喜欢通过错误文本来区分这些错误。还有其他区分方式吗?

function TDNSChecker.CheckServer(host: string): Boolean;
var
  dr: TIdDNSResolver;
begin
  Result := False;
  try
    dr := TIdDNSResolver.Create(nil);
    try
      dr.Host := host;
      dr.QueryType := [qtA];
      dr.WaitingTime := 1000;
      dr.Resolve('feufgzrfapoduiuzgfuzfsufseuszfu'); //knowingly non-existent name
      Result := True;
    finally
      _finished := True;
      dr.Free();
    end;
  except
    on ex: EIdDnsResolverError do
      if ex.Message <> 'TimedOut' then begin
        if (ex.Message = 'DNS Server Reports Query Name Error') or (ex.Message = 'DNS Server Reports Query Server Error') then
          Result := True
        else
          Log(host + ' - ' + ex.ClassName + ': ' + ex.Message.Replace(#13#10, ' '));
      end;
    on ex: Exception do;
  end;
end;

不幸的是,TIdDNSResolver 目前不对不同的 DNS 错误使用不同的异常 class 类型,它只使用 EIdDnsResolverError。我在 Indy 的问题跟踪器中有 opened a ticket,可能会在未来的版本中添加更多错误 classes。

因此,与此同时,要区分 DNS 错误,您必须查看异常 Message 属性。可能的错误消息作为资源字符串存储在 IdResourceStringsProtocols 单元中(大约有 21 个与 DNS 错误相关的字符串)。请注意,其中一些是格式化字符串,因此按原样进行简单比较是行不通的,您将不得不使用类似 TextStartsWith() 或类似的东西来忽略任何格式化部分。

另一方面,如果您收到 EIdDnsResolverError 异常,通常 意味着您收到了来自 DNS 服务器的响应。您不需要区分每个可能的 Indy DNS 错误就可以知道 DNS 服务器的存在。只有少数 EIdDnsResolverError 错误与连接本身有关,例如 RSDNSTimeoutRSTunnelConnectToMasterFailed 等,而不是与 DNS 消息传递的内容有关。

如果您使用的 Delphi 版本具有 Exception.InnerException 属性 可用,则 InnerException 可以设置为 EIdConnectTimeoutEIdConnectExceptionTIdDNSResolver 使用 TCP(仅当 qtAXFRqtIXFR 出现在 QueryType 中时)而不是 UDP。 InnerException 也有可能是 EIdNotEnoughData,但那是消息传递错误,而不是连接错误。

在您的示例中,将使用 UDP,因此我认为除了 RSDNSTimeout 之外的任何 EIdDNSResolverError 错误都表明存在 DNS 服务器。