DNS client を自作する
可能な限り CPAN mobule に依存する + rawsocket という条件付きで DNS client を Perl で書いてみた。
#!/usr/local/bin/perl use strict; use warnings; use IO::Interface::Simple; use IO::Socket::INET; use Net::DNS::Packet; use Net::RawIP qw(:pcap); use App::Options( values => \%ARGV, option => { name => { type => 'string', required => 1, }, ns => { type => 'string', required => 1, }, type => { type => 'string', default => 'A', }, localport => { type => 'int', default => 53, }, }, ); # get local address from interface my $saddr; my @interfaces = IO::Interface::Simple->interfaces; for my $if (@interfaces) { if ( not $if->is_loopback and $if->is_running and $if->is_broadcast ) { $saddr = $if->address; last; } } my $server = IO::Socket::INET->new( Proto => 'udp', LocalPort => $ARGV{localport}, ); my $dns_query = Net::DNS::Packet->new( $ARGV{name}, $ARGV{type}, 'IN' ); my $udp = Net::RawIP->new( { udp => {} } ); $udp->set( { ip => { saddr => $saddr, daddr => $ARGV{ns}, }, udp => { source => $ARGV{localport}, dest => 53, data => $dns_query->data, }, } ); $udp->send; $server->recv( my $msg, 65535 ) or die "recv failed : $!\n"; my $dns_response = Net::DNS::Packet->new( \$msg ); print $dns_response->string;
実行するとこんな感じ
# ./dns_client.pl --name=d.hatena.ne.jp --ns=ns0.future-s.com ;; HEADER SECTION ;; id = 45073 ;; qr = 1 opcode = QUERY aa = 1 tc = 0 rd = 1 ;; ra = 1 ad = 0 cd = 0 rcode = NOERROR ;; qdcount = 1 ancount = 1 nscount = 2 arcount = 2 ;; QUESTION SECTION (1 record) ;; d.hatena.ne.jp. IN A ;; ANSWER SECTION (1 record) d.hatena.ne.jp. 86400 IN A 59.106.108.77 ;; AUTHORITY SECTION (2 records) hatena.ne.jp. 86400 IN NS ns0.future-s.com. hatena.ne.jp. 86400 IN NS ns1.future-s.com. ;; ADDITIONAL SECTION (2 records) ns0.future-s.com. 600 IN A 219.99.160.180 ns1.future-s.com. 600 IN A 219.99.160.181