in reply to Re: How to create DNS packet
in thread How to create DNS packet

Dealing with the responses is where it gets interesting.

You need a way to handle the response packet as an array of bytes/8-bit-characters. Inter alia, the name compression requires this.

You could split the response packet into an array @resp = map { ord($_) } split(//, $response) ; and proceed in a C-like fashion to process that as an array of unsigned 8-bit integers -- reconstructing 16-bit integers and character strings.

Or you can process the string containing response packet directly: using either substr($response, $p, $n) or unpack("\@$p ....", $response) -- where $p is your current "pointer" into the packet.

One way of using unpack to extract a name is to step along it and count the labels, so you can then unpack it much as you've suggested. This:

my $n = 0 ; my $s = $p ; my $l ; do { if ($l = unpack("\@$p C", $response)) { $n++ ; } ; $p += $l + 1 ; } while ($l) ;
sets $n to the number of labels, $s to the start of the name and advances $p past the name in the response packet $response. Then join('.', unpack("\@$s (C/a*)$n", $response)) will do the business. (Compressed names require a bit more code than this, of course.)

As you have found, you need to process the response piece-meal, because you cannot:

my ( ...., @labels, undef, $type, $class, ...) = unpack(".... (C/a*) +$n C n n ....") ;
So a number of unpack operations with '@' are required, each using your $p to start processing in the right place in the response.

I'd knock up a subroutine to extract a name from a given position in the current resoonse packet. You'll want it to return two things, the name and the position just after the name. Since you're new to Perl, you'll need to learn either that a subroutine can return a list (in List Context, of course), so:

($name, $p) = extract_name($response, $p) ; .... sub extract_name { my ($response, $p) = @_ ; my $extracted ... .... return ($extracted, $p) ; } ;
or that you can do "call by reference" type things:
sub extract_name { my ($response, $p) = @_ ; my $extracted ... .... $_[1] = $p ; # $_[1] is implicitly a reference to the 2nd +actual argument return $extracted ; } ;
Enjoy !

Replies are listed 'Best First'.
Re^3: How to create DNS packet
by tokhi (Initiate) on Nov 27, 2008 at 21:05 UTC
    Dear all, can some one please explain this part of the post a little bit more in detail? its from the upper post, I could not get the following part:
    ----------------------------------
    So a number of unpack operations with '@' are required, each using your $p to start processing in the right place in the response.
    I'd knock up a subroutine to extract a name from a given position in the current resoonse packet. You'll want it to return two things, the name and the position just after the name. Since you're new to Perl, you'll need to learn either that a subroutine can return a list (in List Context, of course), so:
    ($name, $p) = extract_name($response, $p) ; .... sub extract_name { my + ($response, $p) = @_ ; my $extracted ... .... return ($extracted, $p +) ; } ;
    or that you can do "call by reference" type things:
    sub extract_name { my ($response, $p) = @_ ; my $extracted ... .... $_[1] = $p ; # $_[1] is implicitly a reference to the 2nd +actual argument return $ +extracted ; } ;
    ------------------------------