Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Replicating Net::DNS::Packet

by Anonymous Monk
on Jun 07, 2014 at 05:48 UTC ( [id://1089118]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to replicate the below code, but with no modules.. Now i'm sure it can be done with the pack() function, but im trying to replicate the Exact responce below (This how i would do it with Net::DNS::Packet:
my $dnspacket = new Net::DNS::Packet( 'www.google.com, 'IN', 'ANY' ); $dnspacket->header->qr(0); #Query Responce Flag $dnspacket->header->aa(0); #Authoritative Flag $dnspacket->header->tc(0); #Truncated Flag $dnspacket->header->ra(0); #Recursion Desired $dnspacket->header->rd(1); #Recursion Available $udp_max = $dnspacket->header->size(1024);
The domain im querying changes per request. which is why i need that to somehow be an option before packing. Im currently using Net::DNS, i have reasons for not wanting to use it. Mainly being its a pain, and i rather do it raw. I was looking at this thread: http://www.perlmonks.org/?node_id=724155 if i could just set my flags, and set the domain to query. (which looks like its already an option from that solution on the thread) Pretty stumped here.

Replies are listed 'Best First'.
Re: Replicating Net::DNS::Packet
by moritz (Cardinal) on Jun 07, 2014 at 07:50 UTC

    A classic: Yes, even you can use CPAN

    Anyway, it's actually pretty simple. Since all arguments are literals and thus constants, you install Net::DNS::Packet on one machine once, dump $dns_packet->data(), and use the resulting string by copy&paste wherever you want to use it.

    Update: Small nit:

    $dnspacket->header->ra(0); #Recursion Desired $dnspacket->header->rd(1); #Recursion Available

    The comments are the wrong way around, the should be switched.

Re: Replicating Net::DNS::Packet
by Anonymous Monk on Jun 07, 2014 at 06:28 UTC
    So i found this:
    use IO::Socket; $hostname = $ARGV[0]; $defdomain = ".oog.org"; # default domain if not present @servers = qw(nameserver1 nameserver2 nameserver3); # name of the name + servers foreach $server (@servers) { &lookupaddress($hostname,$server); # populates %resul +ts } %inv = reverse %results; # invert the result hash if (scalar(keys %inv) > 1) { # see how many elements it has print "There is a discrepancy between DNS servers:\n"; use Data::Dumper; print Data::Dumper->Dump([\%results],["results"]),"\n"; } sub lookupaddress{ my($hostname,$server) = @_; my($qname,$rname,$header,$question,$lformat,@labels,$count); local($position,$buf); ### ### Construct the packet header ### $header = pack("n C2 n4", ++$id, # query id 1, # qr, opcode, aa, tc, rd fields (only rd set) 0, # rd, ra 1, # one question (qdcount) 0, # no answers (ancount) 0, # no ns records in authority section (nscount) 0); # no addtl rr's (arcount) # if we do not have any separators in the name of the host, # append the default domain if (index($hostname,'.') == -1) { $hostname .= $defdomain; } # construct the qname section of a packet (domain name in question +) for (split(/\./,$hostname)) { $lformat .= "C a* "; $labels[$count++]=length; $labels[$count++]=$_; } ### ### construct the packet question section ### $question = pack($lformat."C n2", @labels, 0, # end of labels 1, # qtype of A 1); # qclass of IN ### ### send the packet to the server and read the response ### $sock = new IO::Socket::INET(PeerAddr => $server, PeerPort => "domain", Proto => "udp"); $sock->send($header.$question); # we're using UDP, so we know the max packet size $sock->recv($buf,512); close($sock); # get the size of the response, since we're going to have to keep # track of where we are in the packet as we parse it (via $positio +n) $respsize = length($buf); ### ### unpack the header section ### ($id, $qr_opcode_aa_tc_rd, $rd_ra, $qdcount, $ancount, $nscount, $arcount) = unpack("n C2 n4",$buf); if (!$ancount) { warn "Unable to lookup data for $hostname from $server!\n"; return; } ### ### unpack the question section ### # question section starts 12 bytes in ($position,$qname) = &decompress(12); ($qtype,$qclass)=unpack('@'.$position.'n2',$buf); # move us forward in the packet to end of question section $position += 4; ### ### unpack all of the resource record sections ### for ( ;$ancount;$ancount--){ ($position,$rname) = &decompress($position); ($rtype,$rclass,$rttl,$rdlength)= unpack('@'.$position.'n2 N n',$buf); $position +=10; # this next line could be changed to use a more sophisticated # data structure, it currently picks the last rr returned + $results{$server}= join('.',unpack('@'.$position.'C'.$rdlength,$buf)); $position +=$rdlength; } } # handle domain information that is "compressed" as per RFC1035 # we take in the starting position of our packet parse and return # the name we found (after dealing with the compressed format pointer) # and the place we left off in the packet at the end of the name we fo +und sub decompress { my($start) = $_[0]; my($domain,$i,$lenoct); for ($i=$start;$i<=$respsize;) { $lenoct=unpack('@'.$i.'C', $buf); # get the length of label if (!$lenoct){ # 0 signals we are done with this sectio +n $i++; last; } if ($lenoct == 192) { # we've been handed a pointer, so recurs +e $domain.=(&decompress((unpack('@'.$i.'n',$buf) & 1023)))[1 +]; $i+=2; last } else { # otherwise, we have a plain label $domain.=unpack('@'.++$i.'a'.$lenoct,$buf).'.'; $i += $lenoct; } } return($i,$domain); }
    That looks perfect for what i need, but how would i actually set this up to print out the packet? I don't have enough networking knowledge to understand this to be honest. So if anyone can modify it for me, it would be greatly appreciated and save me ALOT of time.
      Greetings, AM.

      This looks like something that's w-a-y over your head -- no offence intended.

      Problem with something like that, is that you're attempting to use code/scripts you have no knowledge of. THIS IS A DANGEROUS POLICY. You should never adopt such a policy, as you have no knowledge of the potential consequences. Which can be substantial.

      Did you intend to put this script on a (your) web site? Yes? Do you know what can happen if somebody puts something in one of the form fields that wasn't what it was intended for? Very bad things WILL happen if they do. Wipe your (hard) drive, hijack your computer, lift your sensitive data. Ever buy something online with a credit card? Have any idea how much of that information, still resides on your computer? More than you probably realize.

      Sure. I've made a pretty big deal out of this, and you're probably thinking that I'm just exaggerating. Truth is; I am NOT. Everything I just stated, is ABSOLUTE FACT.

      Logistically speaking; if you don't know much about networks. This script is not for you. You probably can't set it up to work on your system w/o a great deal of trouble. I'm quite sure you're not running a local DNS. So you'll have to try your upstream's DNS. They might have provisions that prevent you from obtaining the data you're trying to retrieve. DNS managers have strict policies where their zones, and data management are concerned. They almost never permit recursive queries. Else they become a DNS server for the entire internet -- gratis. It also leads to potential cache-poisoning. Which means all their zones get hijacked. So without a fair amount of knowledge, where the DNS is concerned, and Networking, in general. Your efforts will likely be in vain.

      Best wishes.

      --Chris

      P.S.

      That script is a bit dated. For example, headers haven't had a 512k limit since ~2000.

      ¡λɐp ʇɑəɹ⅁ ɐ əʌɐɥ puɐ ʻꜱdləɥ ꜱᴉɥʇ ədoH

Re: Replicating Net::DNS::Packet
by Anonymous Monk on Jun 07, 2014 at 07:00 UTC

    ... Pretty stumped here.

    :) There is an obvious solution, an existing wheel so to say

      OK.

      Maybe there are better solutions. In fact there are. It's not like I didn't want to help, or anything. I'm just saying. That's all. Making DNS queries is just fine. It's how you find things on the interweb. But there are "rules of engagement". Where your own safety, is concerned. You're going to have to learn, or find some way to "sanitize" your input fields. So, others can't poison them with data, you don't want in them.

      Sure, any one of us could cobble up the entire script -- subs, routines, functions, and forms. But that's a bit much to ask. Don't you think?

      See if you can find something that kind of makes sense to you. Then try to work it out. If you get into trouble. Come, and ask. Show us what you got, and what you've tried, and what went wrong. Then any one of would surely be ready to lend a hand. Sounds about right. Doesn't it?

      We all had to learn Perl. That's what this is all about. :)

      Best wishes.

      --Chris

      ¡λɐp ʇɑəɹ⅁ ɐ əʌɐɥ puɐ ʻꜱdləɥ ꜱᴉɥʇ ədoH

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1089118]
Approved by boftx
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (2)
As of 2024-04-16 21:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found