【问题标题】:How to query gateway for DNS adress by Python or Perl如何通过 Python 或 Perl 查询网关的 DNS 地址
【发布时间】:2026-01-14 16:40:01
【问题描述】:

Linux/Windows 可以从路由器获取 DNS 地址

我需要编写一个本地 dns 代理,我怎样才能像操作系统一样获取 DNS 服务器地址,是否有任何 Perl 或 Python 模块可以做到这一点?

更新

问题应该很清楚,我需要一些东西来模拟接口启动和与本地路由器通信的协议,我不能在接口启动之前进行 tcpdump。不确定 Internet 上是否有示例跟踪文件。可能不是我不熟悉的IP协议。

更新2

由于我使用本地DNS代理服务器,TCP配置如图所示

如果我查询 Net::DNS::Resolver,我会得到结果:127.0.0.1 这不是我需要的

【问题讨论】:

    标签: python perl dns dhcp


    【解决方案1】:

    gethostbyname 使用底层操作系统库的解析器函数。如果您想更直接地访问 DNS 数据包,请使用Net::DNS::Resolver

    【讨论】:

    • Net::DNS::Resolver 需要已知的 DNS 服务器,问题是如何知道 DNS 服务器名
    • @Boying: Net::DNS::Resolver 尝试使用系统的常规设置,如果没有给出明确的服务器,请参阅metacpan.org/pod/Net::DNS::Resolver#new
    • @Boying:我的回复实际上不需要任何更改。您已将 127.0.0.1 配置为本地 DNS 服务器,因此这就是您所获得的,与操作系统所获得的相同。如果您想自己从 DHCP 获取 DNS,但不希望操作系统从 DHCP 获取 DNS,那么您需要自己处理所有 DHCP。
    • 您好 Steffen,所以问题是是否有合适的模块处理所有 DHCP 消息?或者我必须精简协议并使用 Net::Packet::Layer2 来处理它?
    • @Boying:有modules to handle DHCP packets,但您仍然需要先使用Net::Pcap 或类似的方式捕获数据包,具体取决于操作系统。
    【解决方案2】:

    支持 Steffen 答案的非常长的格式化评论。

    TLDR:Steffen 是正确的(+1 BTW)。 Net::DNS::Resolver 应该会为您提供所需的信息。

    示例:

    #!perl
    use strict;
    use warnings;
    
    use Net::DNS::Resolver;
    
    #configure a resolver object using your OS's current config.
    my $resolver = Net::DNS::Resolver->new;
    
    print join "\n", $resolver->nameservers;
    

    在 Windows 和 OS X 上测试。


    如果您认真地寻求上吊自己的绳索,那么您要询问的协议是 DHCP(动态主机配置协议)。

    像您的操作系统一样使用 DHCP,不仅仅是对 DNS 服务器的“查询”,而是对 IP 地址的(新的/更新的)租用的请求。包括网关、时间服务器和 DNS 服务器之类的东西也很重要,但也是次要的。如果操作不当,您可能会搞砸您的操作系统和 DHCP 服务器之间的关系,或者让您的 DHCP 服务器相信您的程序是网络上的另一台(虚假)机器,它应该为其维护租约信息。

    【讨论】:

    • 不幸的是,我需要模拟操作系统行为,因为 DNS 配置为 127.0.0.1,这不是真正的本地 DNS
    • @Boying,大多数人会在手动覆盖之前捕获“良好”的 DNS 数据,但每个人都有自己的数据。如果您不想暂时撤消更改并将其保存在配置文件中,您始终可以使用 Google 的 DNS (8.8.8.8) 或 OpenDNS,这两者都可能比您的 ISP 更好。如果一切都失败了,您仍然可以选择向 DHCP 服务器撒谎。
    • 不幸的是我在中国,所以这些DNS不稳定,有时我在公司的网络中,它是另一个用于内网的DNS
    • 感谢帮助!看我的回答。
    【解决方案3】:

    灵感来自 Steffen Ullrich 我通过管理获取 DHCP 跟踪并由 Net::DHCP::Packet 模拟解决了这个问题,幸运的是它是简单的 UDP 协议

    在使用脚本之前,您需要找出 IP/Mac/GW 地址

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use IO::Socket::INET;
    use Net::DHCP::Packet;
    use Net::DHCP::Constants;
    srand();
    
    # creat DHCP Packet
    my $discover = Net::DHCP::Packet->new(
        Xid                     => int(rand(0xFFFFFFFF)),    # random xid
        Flags                   => 0x0000,                   
        DHO_DHCP_MESSAGE_TYPE() => DHCPREQUEST(),
    );
    $discover->ciaddr('192.168.1.5');
    $discover->chaddr('5cc5d43ca078');
    
    my $handle = IO::Socket::INET->new(
        Proto     => 'udp',
        ReuseAddr => 1,
        PeerPort  => '67',
        LocalPort => '68',
        PeerAddr  => '192.168.1.1'
    ) or die "socket: $@";
    
    $handle->send($discover->serialize());
    my $newmsg;
    if ($handle->recv($newmsg, 1024)) {
        my $packet = Net::DHCP::Packet->new($newmsg);
        print STDERR $packet->toString();
    }
    

    执行结果:

    op = BOOTREPLY
    htype = HTYPE_ETHER
    hlen = 6
    hops = 0
    xid = eaba416c
    secs = 0
    flags = 0
    ciaddr = 192.168.1.5
    yiaddr = 192.168.1.5
    siaddr = 0.0.0.0
    giaddr = 0.0.0.0
    chaddr = 5cc5d43ca078
    sname =
    file =
    Options :
     DHO_DHCP_MESSAGE_TYPE(53) = DHCPACK
     DHO_SUBNET_MASK(1) = 255.255.255.0
     DHO_ROUTERS(3) = 192.168.1.1
     DHO_DOMAIN_NAME_SERVERS(6) = 192.168.1.1
     DHO_DHCP_SERVER_IDENTIFIER(54) = 192.168.1.1
     DHO_DHCP_LEASE_TIME(51) = 86400
     DHO_VI_VENDOR_SPECIFIC_INFOMATION(125) = \x00\x00\x00\x00\x14\x02\x06HGW-CT\x0A\x02\x00\x00\x0B\x02\x00U\x0D\x02\x00.
    padding [247] = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    

    我们可以看到

    DHO_DOMAIN_NAME_SERVERS(6) = 192.168.1.1
    

    是DNS服务器地址

    【讨论】:

    • 在此之后,人们不得不怀疑您的计算机和您的 DHCP 服务器是否仍然同意您的租约到期。
    • 我在设置/取消设置手动DNS时tcpdump了接口,这种行为在Windows上是允许的,然后用perl模拟了这个行为。我认为它不会影响现有的 ip/gw 和相关的租用时间。