使用VB6指定DNS服务器查找IP地址对应的主机名

4
我知道如何使用GetHostByAddr Windows API调用在VB中查找IPv4的主机名(this很好用)。然而,该函数不允许指定要使用的DNS服务器。有时默认公司DNS服务器很好,但其他时候我需要指定外部DNS服务器进行查找,我认为不应该通过执行shell nslookup并解析输出来完成这一点。

注意:实际上,这将作为Excel工作簿中的VBA代码来使用,以帮助其他人完成他的工作,当他只需要一些简单的功能时,编写大型应用程序是不值得的。

我曾经认为在API调用getnameinfo中可能找到了答案,但仔细阅读似乎表明它没有提供servername参数。

经过一番激烈的搜索,我找到了DNSQuery函数中pExtra参数的相关参考。但我甚至不知道如何在VB6中开始使用它。

有人能以任何方式帮我从VB6进行DNS查找,指定要使用的服务器名称吗?

当然,一个完整的工作解决方案会很好,但只需指点我正确的方向我也愿意努力。

更新:由于某种奇怪的原因,我没有想到DNSQuery是一个Windows API调用。它听起来并不像一个。如果我注意到这个细节,我肯定能在问题上取得更多进展。

3个回答

4

试试这个:

Option Explicit

Private Declare Function DnsQuery Lib "dnsapi" Alias "DnsQuery_A" (ByVal strname As String, ByVal wType As Integer, ByVal fOptions As Long, ByVal pServers As Long, ppQueryResultsSet As Long, ByVal pReserved As Long) As Long
Private Declare Function DnsRecordListFree Lib "dnsapi" (ByVal pDnsRecord As Long, ByVal FreeType As Long) As Long
Private Declare Function lstrlen Lib "kernel32" (ByVal straddress As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, ByVal Source As Long, ByVal Length As Long)
Private Declare Function inet_ntoa Lib "ws2_32.dll" (ByVal pIP As Long) As Long
Private Declare Function inet_addr Lib "ws2_32.dll" (ByVal sAddr As String) As Long

Private Const DnsFreeRecordList         As Long = 1
Private Const DNS_TYPE_A                As Long = &H1
Private Const DNS_QUERY_BYPASS_CACHE    As Long = &H8

Private Type VBDnsRecord
    pNext           As Long
    pName           As Long
    wType           As Integer
    wDataLength     As Integer
    flags           As Long
    dwTel           As Long
    dwReserved      As Long
    prt             As Long
    others(35)      As Byte
End Type

Private Sub Command1_Click()
    MsgBox Resolve("google.com", "208.67.222.222")
End Sub

Private Function Resolve(sAddr As String, Optional sDnsServers As String) As String
    Dim pRecord     As Long
    Dim pNext       As Long
    Dim uRecord     As VBDnsRecord
    Dim lPtr        As Long
    Dim vSplit      As Variant
    Dim laServers() As Long
    Dim pServers    As Long
    Dim sName       As String

    If LenB(sDnsServers) <> 0 Then
        vSplit = Split(sDnsServers)
        ReDim laServers(0 To UBound(vSplit) + 1)
        laServers(0) = UBound(laServers)
        For lPtr = 0 To UBound(vSplit)
            laServers(lPtr + 1) = inet_addr(vSplit(lPtr))
        Next
        pServers = VarPtr(laServers(0))
    End If
    If DnsQuery(sAddr, DNS_TYPE_A, DNS_QUERY_BYPASS_CACHE, pServers, pRecord, 0) = 0 Then
        pNext = pRecord
        Do While pNext <> 0
            Call CopyMemory(uRecord, pNext, Len(uRecord))
            If uRecord.wType = DNS_TYPE_A Then
                lPtr = inet_ntoa(uRecord.prt)
                sName = String(lstrlen(lPtr), 0)
                Call CopyMemory(ByVal sName, lPtr, Len(sName))
                If LenB(Resolve) <> 0 Then
                    Resolve = Resolve & " "
                End If
                Resolve = Resolve & sName
            End If
            pNext = uRecord.pNext
        Loop
        Call DnsRecordListFree(pRecord, DnsFreeRecordList)
    End If
End Function

太棒了,谢谢你。你是从库中获取还是为这个答案定制的呢? - ErikE
不得不自定义清理一些来自“代码浴室墙”的样本 :-)) - wqw
@wqw:我已经想出了一个相当精练的工作函数。既然我要求反向查找,我希望你提到我需要反转IP地址并在末尾添加.in-addr.arpa以进行反向查找。我还必须使用DNS_TYPE_PTR而不是A,这需要花费相当长的时间来调试。由于你对我的最终解决方案做出了实质性的贡献,我接受了你的答案。你的代码还需要Split(sDnsServers, ",")或其他指定的分隔符。我必须说,我不喜欢你使用的匈牙利命名法风格。 - ErikE
1
Split无需分隔符,只需在空格上拆分,因此您可以将“8.8.8.8 8.8.4.4”(Google公共DNS)用于sDnsServers参数。我很高兴匈牙利语是你在这里最明显的问题。我已经在这个行业里待了足够长的时间,看到匈牙利语出现,然后被否定,然后可能再次作为应用程序匈牙利语(http://www.joelonsoftware.com/articles/Wrong.html)。不要为此烦恼,不使用系统匈牙利语并不比使用它更好。这不是您可以正确或错误的事情,世界上99%的VB6代码都是使用系统匈牙利语修饰的。 - wqw
我不知道Split默认使用空格。谢谢。应用程序匈牙利命名法是我使用的,我熟悉那篇文章。我正在尽我所能,将全球VB6系统匈牙利代码降至98%!系统匈牙利不是道德上或事实上对或错,但实际上是错误的!它只会毫无意义地使一切变得混乱。我理解风格是主观的,但风格仍然很重要。非常重要!它还会影响理解速度。 - ErikE
你有没有注意到我只在API函数上使用Call。这是VB部分的风格。匈牙利命名法——当你阅读C/C++ WinAPI代码时,你会看到同样数量的它。事实上,不使用它可能会降低某人对这种API代码的理解能力,我认为。无论如何,98%是一个很好的目标 :-))) - wqw

0
你可以使用DNS WMI提供程序来设置系统的DNS,然后使用GetHostByAddr函数。

我会检查并了解用户是否同意,但我怀疑他不会(我也不喜欢这样做),因为如果需要更改回去,则可能会发生错误,导致它指向错误的DNS服务器,这是不可以的。 - ErikE
这是遗留代码的一部分还是您有一些自由度可以利用像.net这样的新框架? - joejoeson
这只是一些自动化工具,帮助网络安全人员完成他的工作。我花了大约30分钟为他“整理”了一下Excel工作簿。他还问我是否可以给他一个参数来指定服务器名称。现在我很好奇!如果需要编写整个应用程序,那么我可以尽情使用C#。但是Excel(2003)已经满足了他99%的需求。 - ErikE

0

这不是一个答案,而是对wqw post非常重要的注释:

安全警告关于lstrlen函数(第5行和第55行):

使用此函数不正确可能会危及您的应用程序的安全性lstrlen假定lpString是以null结尾的字符串或NULL。如果不是,则可能导致缓冲区溢出或拒绝服务攻击针对您的应用程序。

考虑使用以下替代方案之一:StringCbLengthStringCchLength


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接