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

Hello everyone,

I've recently been using Net::DNS as part of a project at work, and have been blocked by this bug.

It appears that subroutine new_from_string is too naive when stripping comments, and fails to cope with semi-colons embedded within TXT data.

I'm proposing the following simple patch to resolve this, and would like the opinions of the brethren before I consider passing it on to the maintainer.

The patched code passes all the tests provided with the current (v0.48) Net::DNS distribution.

Thanks in advance for any comments.

--- Net-DNS-0.48/lib/Net/DNS/RR.pm 2004-08-12 06:48:00.000000000 ++0100 +++ SC-Net-DNS-0.48/lib/Net/DNS/RR.pm 2004-12-13 15:56:19.583003131 ++0000 @@ -250,9 +250,6 @@ build_regex() unless $RR_REGEX; - # strip out comments - $rrstring =~ s/;.*//g; - ($rrstring =~ m/$RR_REGEX/xso) || confess qq|qInternal Error: "$rrstring" did not match +RR pat.\nPlease report this to the author!\n|; @@ -265,8 +262,20 @@ my $rdata = $5 || ''; $rdata =~ s/\s+$// if $rdata; - $name =~ s/\.$// if $name; + # strip out comments + if($rrtype eq 'TXT') { + if(($rdata)=~m[;]) { + if(($rdata)=~m[^(".*")($|\s*;)]) { + $rdata = $1; + } else { + ($rdata)=~s/;.*//g; + } + } + } else { + ($rdata)=~s/;.*//g; + } + $name =~ s/\.$// if $name; # RFC3597 tweaks # This converts to known class and type if specified as TYPE## +#

Replies are listed 'Best First'.
Re: Net::DNS::RR patch
by ikegami (Patriarch) on Dec 13, 2004 at 16:34 UTC
    Why not just change the regexp to
    $rrstring =~ s/^((?:[^\n;]+|"(?:[^\n"\\]|\\[^\n])*")*);[^\n]*$/$1/mg;
    What you presented only helps TXT records (even though it's not the only one that can have strings), and doesn't allow embeded quotes ("dd\"dd") even though the spec does.

      I accept your point about only applying the test to TXT records, and have modified the proposed patch accordingly.

      However, your regex doesn't work for the observed bug. Using the code from twilde's original bug report:

      Your regex:

      my $rr = Net::DNS::RR->new_from_string( 'badtxt.krellis.us. 1234 TXT "something ;something else"' ); print '"', $rr->rr_rdata, '"', "\n";

      Gives:

      ""

      My patch gives:

      "something ;something else"

      I also disagree with you assertion that the patch won't allow backslashed quotes within TXT RDATA. e.g.:

      my $rr = Net::DNS::RR->new_from_string( 'badtxt.krellis.us. 1234 TXT "something \" ; \" something else"' ); print '"', $rr->rr_rdata, '"', "\n";

      Gives:

      "something " ; " something else"
        However, your regex doesn't work

        You're right here. I deleted a " by accident. Here's the fix:

        $rrstring =~ s/^((?:[^\n";]+|"(?:[^\n"\\]|\\[^\n])*")*);[^\n]*$/$1/mg; ^ was missing
        I also disagree with you assertion that the patch won't allow backslashed quotes within TXT RDATA.

        It completely ignores backslashes, so I knew there was a problem. I was only wrong in how it fails. Your patch does allow backslashes, but it incorrectly finds the end of the quoted string.

        Here's a string where it fails to work:

        # Here's the simplest case where it fails: # $expect = "\"Joe\""; # $rdata = $expect . " ; \"comment\""; $expect = "\"John \\\"The Wiz\\\" Doe; programmer\""; $rdata = $expect . " ; \"comment\""; print("Input: ", $rdata, $/); print("Expect: ", $expect, $/); if(($rdata)=~m[;]) { if(($rdata)=~m[^(".*")($|\s*;)]) { $rdata = $1; } else { ($rdata)=~s/;.*//g; } } print("Get: ", $rdata, $/); __END__ output ====== Input: "John \"The Wiz\" Doe; programmer" ; "comment" Expect: "John \"The Wiz\" Doe; programmer" Get: "John \"The Wiz\" Doe; programmer" ; "comment"

        btw, the /g in ($rdata)=~s/;.*//g; is not necessary.