1

我遇到的问题是因为在我的以太网接口上启用了 IPv6 - 所以当我不想要它们时,主机名解析有时会产生 IPv6 结果。

是否可以让 twisted.names.client返回 ipv4 地址而不对操作系统/名称解析/以太网配置进行任何更改?

示例代码:

#!/usr/bin/python

from twisted.internet import defer, reactor
from twisted.names import client

def got_arg(*args):
    print 'got_arg',args

def get_arg(arg):
    d = client.getHostByName('www.google.com').addCallback(got_arg)

if __name__ == '__main__':
    get_arg('www.google.com')
    reactor.run()

这段代码总是在我的 Linux 机器上给我一个 ipv6 地址:

got_arg ('2001:4860:4001:800::1010',)

我希望能够强制进行 ipv4 查找,而无需修改下面的任何内容。有任何想法吗?由于缺乏强制,至少有一个结果被 ipv4/ipv6 分解的字典或元组会很好。

4

1 回答 1

3

我想通了..您必须使用 client.lookupAllRecords 然后测试返回的记录类型..

#!/usr/bin/python

from twisted.internet import defer, reactor
from twisted.names import client, dns

def got_arg(*args):
    for a in args[0][0]:
        if a.payload.TYPE == dns.A:
            print 'A    - ipv4',a.payload
        elif a.payload.TYPE == dns.AAAA:
            print 'AAAA - ipv6',a.payload


def get_arg(arg):
    d = client.lookupAllRecords('www.google.com').addCallback(got_arg)

if __name__ == '__main__':
    get_arg('www.google.com')
    reactor.run()

编辑

我意识到这个解决方案是不够的——特别是在第一批记录只包含一个指向另一个地址的 CNAME 的情况下。

原因是 twisted.names.common.extractRecord() 首先查找 ipv6 地址并立即返回它们 - 没有明显的机制来覆盖此行为。

因此,我为此制定了一个 hacky 解决方案,这样我们甚至不会尝试通过制作丑陋的猴子补丁来解决 ipv6 地址的链条。

#!/usr/bin/python

import socket
from twisted.names import dns
from twisted.names import common

def myExtractRecord(resolver, name, answers, level=10):
    if not level:
        return None
    for r in answers:
        if r.name == name and r.type == dns.A:
            return socket.inet_ntop(socket.AF_INET, r.payload.address)
    for r in answers:
        if r.name == name and r.type == dns.CNAME:
            result = myExtractRecord(
                resolver, r.payload.name, answers, level - 1)
            if not result:
                return resolver.getHostByName(
                    str(r.payload.name), effort=level - 1)
            return result
    # No answers, but maybe there's a hint at who we should be asking about
    # this
    for r in answers:
        if r.type == dns.NS:
            from twisted.names import client
            r = client.Resolver(servers=[(str(r.payload.name), dns.PORT)])
            return r.lookupAddress(str(name)
                ).addCallback(
                    lambda (ans, auth, add):
                        myExtractRecord(r, name, ans + auth + add, level - 1))

common.extractRecord = myExtractRecord

我把它放在 dnsclient.py 中,并通过以下方式在我的主编中使用它:

from twisted.names import client
import dnsclient

如果对此有更优雅的解决方案,我会全力以赴。我认为如果 getHostByName 接受 dns.A,dns.AAAA,dns.A && dns.AAAA 的掩码来确定要遍历树的记录,这会更友好。

于 2012-12-11T13:11:18.547 回答