From d3f7e396b399badc55199b37a6cbab397239e656 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Wed, 24 Aug 2022 17:02:19 +0200 Subject: [PATCH 01/27] Debug option --- Makefile.PL | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Makefile.PL b/Makefile.PL index cf5c342..223d0d8 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -58,6 +58,10 @@ The PATH is passed to the LDNS compiler via the CFLAGS variable. Search for OpenSSL library in PATH. The PATH is passed to the LDNS compiler via the LDFLAGS variable. +=item --debug + +Enable debug mode, more verbose output. + =back =cut @@ -69,6 +73,7 @@ my $opt_randomize = 0; my $opt_prefix_openssl = ""; my $opt_openssl_inc = ""; my $opt_openssl_lib = ""; +my $opt_debug = 0; GetOptions( 'ed25519!' => \$opt_ed25519, 'idn!' => \$opt_idn, @@ -77,6 +82,7 @@ GetOptions( 'prefix-openssl=s' => \$opt_prefix_openssl, 'openssl-inc=s' => \$opt_openssl_inc, 'openssl-lib=s' => \$opt_openssl_lib, + 'debug!' => \$opt_debug, ); configure_requires 'Devel::CheckLib'; @@ -125,6 +131,7 @@ else { } cc_assert_lib( + debug => $opt_debug, lib => 'crypto', header => 'openssl/crypto.h', function => 'if(SSLeay()) return 0; else return 1;', @@ -133,6 +140,7 @@ cc_assert_lib( if ( $opt_ed25519 ) { print "Feature Ed25519 enabled\n"; cc_assert_lib( + debug => $opt_debug, lib => 'crypto', header => 'openssl/evp.h', function => 'EVP_PKEY_ED25519; return 0;', @@ -156,6 +164,7 @@ else { cc_libs 'ldns'; if ( $opt_ed25519 ) { cc_assert_lib( + debug => $opt_debug, lib => 'ldns', header => 'ldns/ldns.h', ccflags => '-DUSE_ED25519', From 78b0a216373f915a16655410790e21cb28633d63 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Wed, 24 Aug 2022 17:12:47 +0200 Subject: [PATCH 02/27] Options to provide LDNS and Libidn inc/lib paths Allow passing distinct LDNS and Libidn paths for include and library files when configuring Zonemaster-LDNS. --- Makefile.PL | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index 223d0d8..e583fb1 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -58,6 +58,22 @@ The PATH is passed to the LDNS compiler via the CFLAGS variable. Search for OpenSSL library in PATH. The PATH is passed to the LDNS compiler via the LDFLAGS variable. +=item --libidn-inc=PATH + +Search for Libidn include in PATH. + +=item --libidn-lib=PATH + +Search for Libidn library in PATH. + +=item --ldns-inc=PATH + +Search for LDNS include in PATH. + +=item --ldns-lib=PATH + +Search for LDNS library in PATH. + =item --debug Enable debug mode, more verbose output. @@ -73,6 +89,10 @@ my $opt_randomize = 0; my $opt_prefix_openssl = ""; my $opt_openssl_inc = ""; my $opt_openssl_lib = ""; +my $opt_libidn_inc = ""; +my $opt_libidn_lib = ""; +my $opt_ldns_inc = ""; +my $opt_ldns_lib = ""; my $opt_debug = 0; GetOptions( 'ed25519!' => \$opt_ed25519, @@ -82,6 +102,10 @@ GetOptions( 'prefix-openssl=s' => \$opt_prefix_openssl, 'openssl-inc=s' => \$opt_openssl_inc, 'openssl-lib=s' => \$opt_openssl_lib, + 'libidn-inc=s' => \$opt_libidn_inc, + 'libidn-lib=s' => \$opt_libidn_lib, + 'ldns-inc=s' => \$opt_ldns_inc, + 'ldns-lib=s' => \$opt_ldns_lib, 'debug!' => \$opt_debug, ); @@ -161,12 +185,39 @@ if ( $opt_internal_ldns ) { } else { print "Feature internal ldns disabled\n"; - cc_libs 'ldns'; + + my %assert_lib_args_ldns; + my $custom_ldns = ( $opt_ldns_inc or $opt_ldns_lib ); + if ( $custom_ldns ) { + my $ldns_incpath = ""; + my $ldns_libpath = ""; + + if ( $opt_ldns_inc ) { + print "Custom include directory for LDNS: $opt_ldns_inc\n"; + $ldns_incpath = "$opt_ldns_inc"; + } + + if ( $opt_ldns_lib ) { + print "Custom library directory for LDNS: $opt_ldns_lib\n"; + $ldns_libpath = "$opt_ldns_lib"; + } + + cc_include_paths "$ldns_incpath"; + cc_libs "-L$ldns_libpath", "ldns"; + + $assert_lib_args_ldns{incpath} = "$ldns_incpath"; + $assert_lib_args_ldns{libpath} = "$ldns_libpath"; + } + else { + cc_libs 'ldns'; + } + if ( $opt_ed25519 ) { cc_assert_lib( debug => $opt_debug, lib => 'ldns', header => 'ldns/ldns.h', + %assert_lib_args_ldns, ccflags => '-DUSE_ED25519', function => 'if(LDNS_ED25519) return 0; else return 1;' ); @@ -174,16 +225,44 @@ else { } -# IDN +# Libidn if ( $opt_idn ) { print "Feature idn enabled\n"; + + my %assert_lib_args_libidn; + my $custom_libidn = ( $opt_libidn_inc or $opt_libidn_lib ); + if ( $custom_libidn ) { + my $libidn_incpath = ""; + my $libidn_libpath = ""; + + if ( $opt_libidn_inc ) { + print "Custom include directory for Libidn: $opt_libidn_inc\n"; + $libidn_incpath = "$opt_libidn_inc"; + } + + if ( $opt_libidn_lib ) { + print "Custom library directory for Libidn: $opt_libidn_lib\n"; + $libidn_libpath = "$opt_libidn_lib"; + } + + cc_include_paths "$libidn_incpath"; + cc_libs "-L$libidn_libpath", "idn2"; + + $assert_lib_args_libidn{incpath} = "$libidn_incpath"; + $assert_lib_args_libidn{libpath} = "$libidn_libpath"; + } + else { + cc_libs 'idn2'; + } + check_lib_or_exit( + debug => $opt_debug, lib => 'idn2', header => 'idn2.h', - function => - 'return IDN2_OK;'); - cc_libs 'idn2'; + %assert_lib_args_libidn, + function => 'return IDN2_OK;' + ); cc_define '-DWE_CAN_HAZ_IDN'; } else { From 705887e72f6ee4ad9d5c9bb2ce7d8ac0b3f5f496 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Wed, 24 Aug 2022 18:02:41 +0200 Subject: [PATCH 03/27] Refactoring: factorize code to load library --- Makefile.PL | 195 ++++++++++++++++++++++++++-------------------------- 1 file changed, 98 insertions(+), 97 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index e583fb1..746236c 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -86,27 +86,36 @@ my $opt_ed25519 = 1; my $opt_idn = 1; my $opt_internal_ldns = 1; my $opt_randomize = 0; -my $opt_prefix_openssl = ""; -my $opt_openssl_inc = ""; -my $opt_openssl_lib = ""; -my $opt_libidn_inc = ""; -my $opt_libidn_lib = ""; -my $opt_ldns_inc = ""; -my $opt_ldns_lib = ""; my $opt_debug = 0; +my $opt_assets = { + openssl => { + prefix => "", + inc => "", + lib => "" + }, + ldns => { + inc => "", + lib => "" + }, + libidn => { + inc => "", + lib => "" + } +}; + GetOptions( 'ed25519!' => \$opt_ed25519, 'idn!' => \$opt_idn, 'internal-ldns!' => \$opt_internal_ldns, 'randomize!' => \$opt_randomize, - 'prefix-openssl=s' => \$opt_prefix_openssl, - 'openssl-inc=s' => \$opt_openssl_inc, - 'openssl-lib=s' => \$opt_openssl_lib, - 'libidn-inc=s' => \$opt_libidn_inc, - 'libidn-lib=s' => \$opt_libidn_lib, - 'ldns-inc=s' => \$opt_ldns_inc, - 'ldns-lib=s' => \$opt_ldns_lib, 'debug!' => \$opt_debug, + 'prefix-openssl=s' => \$$opt_assets{openssl}{prefix}, + 'openssl-inc=s' => \$$opt_assets{openssl}{inc}, + 'openssl-lib=s' => \$$opt_assets{openssl}{lib}, + 'libidn-inc=s' => \$$opt_assets{libidn}{inc}, + 'libidn-lib=s' => \$$opt_assets{libidn}{lib}, + 'ldns-inc=s' => \$$opt_assets{ldns}{inc}, + 'ldns-lib=s' => \$$opt_assets{ldns}{lib}, ); configure_requires 'Devel::CheckLib'; @@ -121,45 +130,73 @@ cc_include_paths 'include'; cc_src_paths 'src'; -# OpenSSL +my %assert_lib_args = ( + openssl => {}, + libidn => {}, + ldns => {} +); -my %assert_lib_args_openssl; -my $custom_openssl = ( $opt_prefix_openssl or $opt_openssl_inc or $opt_openssl_lib ); -if ( $custom_openssl ) { - my $openssl_incpath = ""; - my $openssl_libpath = ""; +sub custom_assets +{ + my ( $href ) = @_; + # $href = { key => "openssl", lib => "crypto", name => "OpenSSL" } - if ( $opt_prefix_openssl ) { - print "Custom prefix for OpenSSL: $opt_prefix_openssl\n"; - $openssl_incpath = "$opt_prefix_openssl/include"; - $openssl_libpath = "$opt_prefix_openssl/lib"; - } + my $key = $$href{key}; + my $name = $$href{name}; + my $lib = $$href{lib}; - if ( $opt_openssl_inc ) { - print "Custom include directory for OpenSSL: $opt_openssl_inc\n"; - $openssl_incpath = "$opt_openssl_inc"; - } + my $input_prefix = $$opt_assets{$key}{prefix}; + my $input_inc = $$opt_assets{$key}{inc}; + my $input_lib = $$opt_assets{$key}{lib}; - if ( $opt_openssl_lib ) { - print "Custom library directory for OpenSSL: $opt_openssl_lib\n"; - $openssl_libpath = "$opt_openssl_lib"; - } + my $custom_lib = ( $input_prefix or $input_inc or $input_lib ); + if ( $custom_lib ) { + my $incpath = ""; + my $libpath = ""; - cc_include_paths "$openssl_incpath"; - cc_libs "-L$openssl_libpath", "crypto"; - $assert_lib_args_openssl{incpath} = "$openssl_incpath"; - $assert_lib_args_openssl{libpath} = "$openssl_libpath"; -} -else { - cc_libs 'crypto'; + if ( $input_prefix ) { + print "Custom prefix for $name: $input_prefix\n"; + $incpath = "$input_prefix/include"; + $libpath = "$input_prefix/lib"; + } + + if ( $input_inc ) { + print "Custom include directory for $name: $input_inc\n"; + $incpath = "$input_inc"; + } + + if ( $input_lib ) { + print "Custom library directory for $name: $input_lib\n"; + $libpath = "$input_lib"; + } + + cc_include_paths "$incpath"; + cc_libs "-L$libpath", "$lib"; + + $assert_lib_args{$key}{incpath} = "$incpath"; + $assert_lib_args{$key}{libpath} = "$libpath"; + } + else { + cc_libs "$lib"; + } } +# OpenSSL + +custom_assets( + { + name => "OpenSSL", + lib => "crypto", + key => "openssl" + } +); + cc_assert_lib( debug => $opt_debug, lib => 'crypto', header => 'openssl/crypto.h', function => 'if(SSLeay()) return 0; else return 1;', - %assert_lib_args_openssl, + %{ %assert_lib_args{openssl} }, ); if ( $opt_ed25519 ) { print "Feature Ed25519 enabled\n"; @@ -168,7 +205,7 @@ if ( $opt_ed25519 ) { lib => 'crypto', header => 'openssl/evp.h', function => 'EVP_PKEY_ED25519; return 0;', - %assert_lib_args_openssl, + %{ %assert_lib_args{openssl} }, ); } else { @@ -186,38 +223,20 @@ if ( $opt_internal_ldns ) { else { print "Feature internal ldns disabled\n"; - my %assert_lib_args_ldns; - my $custom_ldns = ( $opt_ldns_inc or $opt_ldns_lib ); - if ( $custom_ldns ) { - my $ldns_incpath = ""; - my $ldns_libpath = ""; - - if ( $opt_ldns_inc ) { - print "Custom include directory for LDNS: $opt_ldns_inc\n"; - $ldns_incpath = "$opt_ldns_inc"; - } - - if ( $opt_ldns_lib ) { - print "Custom library directory for LDNS: $opt_ldns_lib\n"; - $ldns_libpath = "$opt_ldns_lib"; + custom_assets( + { + name => "LDNS", + lib => "ldns", + key => "ldns" } - - cc_include_paths "$ldns_incpath"; - cc_libs "-L$ldns_libpath", "ldns"; - - $assert_lib_args_ldns{incpath} = "$ldns_incpath"; - $assert_lib_args_ldns{libpath} = "$ldns_libpath"; - } - else { - cc_libs 'ldns'; - } + ); if ( $opt_ed25519 ) { cc_assert_lib( debug => $opt_debug, lib => 'ldns', header => 'ldns/ldns.h', - %assert_lib_args_ldns, + %{ %assert_lib_args{ldns} }, ccflags => '-DUSE_ED25519', function => 'if(LDNS_ED25519) return 0; else return 1;' ); @@ -230,37 +249,19 @@ else { if ( $opt_idn ) { print "Feature idn enabled\n"; - my %assert_lib_args_libidn; - my $custom_libidn = ( $opt_libidn_inc or $opt_libidn_lib ); - if ( $custom_libidn ) { - my $libidn_incpath = ""; - my $libidn_libpath = ""; - - if ( $opt_libidn_inc ) { - print "Custom include directory for Libidn: $opt_libidn_inc\n"; - $libidn_incpath = "$opt_libidn_inc"; + custom_assets( + { + name => "Libidn", + lib => "idn2", + key => "libidn" } - - if ( $opt_libidn_lib ) { - print "Custom library directory for Libidn: $opt_libidn_lib\n"; - $libidn_libpath = "$opt_libidn_lib"; - } - - cc_include_paths "$libidn_incpath"; - cc_libs "-L$libidn_libpath", "idn2"; - - $assert_lib_args_libidn{incpath} = "$libidn_incpath"; - $assert_lib_args_libidn{libpath} = "$libidn_libpath"; - } - else { - cc_libs 'idn2'; - } + ); check_lib_or_exit( debug => $opt_debug, lib => 'idn2', header => 'idn2.h', - %assert_lib_args_libidn, + %{ %assert_lib_args{libidn} }, function => 'return IDN2_OK;' ); cc_define '-DWE_CAN_HAZ_IDN'; @@ -316,14 +317,14 @@ END_CONFIGURE_FLAGS my $openssl_make = < Date: Thu, 25 Aug 2022 10:35:25 +0200 Subject: [PATCH 04/27] Fix syntax error --- Makefile.PL | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index 746236c..9f4fc66 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -196,7 +196,7 @@ cc_assert_lib( lib => 'crypto', header => 'openssl/crypto.h', function => 'if(SSLeay()) return 0; else return 1;', - %{ %assert_lib_args{openssl} }, + %{ $assert_lib_args{openssl} }, ); if ( $opt_ed25519 ) { print "Feature Ed25519 enabled\n"; @@ -205,7 +205,7 @@ if ( $opt_ed25519 ) { lib => 'crypto', header => 'openssl/evp.h', function => 'EVP_PKEY_ED25519; return 0;', - %{ %assert_lib_args{openssl} }, + %{ $assert_lib_args{openssl} }, ); } else { @@ -236,7 +236,7 @@ else { debug => $opt_debug, lib => 'ldns', header => 'ldns/ldns.h', - %{ %assert_lib_args{ldns} }, + %{ $assert_lib_args{ldns} }, ccflags => '-DUSE_ED25519', function => 'if(LDNS_ED25519) return 0; else return 1;' ); @@ -261,7 +261,7 @@ if ( $opt_idn ) { debug => $opt_debug, lib => 'idn2', header => 'idn2.h', - %{ %assert_lib_args{libidn} }, + %{ $assert_lib_args{libidn} }, function => 'return IDN2_OK;' ); cc_define '-DWE_CAN_HAZ_IDN'; From 382e543f0ca4140ebeeaa9d07be9fb0223e93bac Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Thu, 25 Aug 2022 10:41:11 +0200 Subject: [PATCH 05/27] Update README with new options --- README.md | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd2c889..4c59d36 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ * [IDN] * [Internal ldns] * [Randomized capitalization](#randomized-capitalization) + * [Custom OpenSSL] + * [Custom LDNS] + * [Custom Libidn] + * [Debug] ## Introduction @@ -175,7 +179,7 @@ Randomizes the capitalization of returned domain names. Disabled by default. Enabled with `--prefix-openssl=/path/to/openssl` or -`--openssl-inc=/path/to/openssl_inc` or `--openssl-lib=/path/to/openssl_lib` +`--openssl-inc=/path/to/openssl_inc` or `--openssl-lib=/path/to/openssl_lib`. Enabling this makes the build tools look for OpenSSL in a non-standard place. @@ -192,6 +196,39 @@ same parent directory, use `--openssl-inc` and `--openssl-lib` options to specify both paths. +### Custom LDNS + +Disabled by default. +Enabled with `--ldns-inc=/path/to/ldns_inc` or `--ldns-lib=/path/to/ldns_lib`. + +Enabling this makes the build tools look for LDNS in a non-standard place. + +> Requires [Internal LDNS] to be disabled. + + +### Custom Libidn + +Disabled by default. +Enabled with `--libidn-inc=/path/to/libidn_inc` or +`--libidn-lib=/path/to/ldns_lib`. + +Enabling this makes the build tools look for Libidn in a non-standard place. + +> Requires [IDN] to be enabled. + + +### Debug + +Disabled by default. +Enabled with `--debug`. + +Gives a more verbose output. + + +[Custom LDNS]: #custom-ldns +[Custom Libidn]: #custom-libidn +[Custom OpenSSL]: #custom-openssl +[Debug]: #debug [DNS::LDNS]: http://search.cpan.org/~erikoest/DNS-LDNS/ [Docker Hub]: https://hub.docker.com/u/zonemaster [Docker Image Creation]: https://github.com/zonemaster/zonemaster/blob/master/docs/internal-documentation/maintenance/ReleaseProcess-create-docker-image.md From 1fbfeb3f022923215e0063d257bf22d92cc30061 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Thu, 1 Sep 2022 15:33:25 +0200 Subject: [PATCH 06/27] Use lowercase fragments for internal reference --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd2c889..6490d06 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ * [Dependencies and Compatibility](#dependencies-and-compatibility) * [Installation and verification](#installation-and-verification) * [Recommended installation](#recommended-installation) - * [Docker](#Docker) + * [Docker](#docker) * [Installation from source](#installation-from-source) * [Post-installation sanity check](#post-installation-sanity-check) * [Testing](#testing) From 945db0e12e33bc2e3157ee553c58f96431ea21ec Mon Sep 17 00:00:00 2001 From: Marc van der Wal Date: Thu, 1 Sep 2022 10:21:23 +0200 Subject: [PATCH 07/27] Add unit tests to reproduce issue on bad CAA RRs Add a unit test in packet.t and another one in rr.t to reproduce the segfaults I observed. See also issue #149. --- t/packet.t | 31 +++++++++++++++++++++++++++++++ t/rr.t | 8 ++++++++ 2 files changed, 39 insertions(+) diff --git a/t/packet.t b/t/packet.t index 0d55feb..8be8565 100644 --- a/t/packet.t +++ b/t/packet.t @@ -28,4 +28,35 @@ is($p->answerfrom, undef, 'No answerfrom'); $p->answerfrom('127.0.0.1'); is($p->answerfrom, '127.0.0.1', 'Localhost'); +subtest "croak when stringifying packet with malformed CAA" => sub { + my $will_croak = sub { + # Constructing a synthetic packet that would have the following string + # representation in dig-like format: + # + # ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 13944 + # ;; flags: qr aa ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 + # ;; QUESTION SECTION: + # ;; bad-caa.example. IN CAA + # + # ;; ANSWER SECTION: + # bad-caa.example. 3600 IN CAA \# 4 C0000202 + # + # ;; AUTHORITY SECTION: + # + # ;; ADDITIONAL SECTION: + my $packet_bin = pack( + 'H*', + '367884000001000100000000' . # header + '076261642d636161076578616d706c650001010001' . # question + 'c00c0101000100000e100004c0000202' # bad answer + ); + + my $packet = Zonemaster::LDNS::Packet->new_from_wireformat( $packet_bin ); + + # This must croak + $packet->string; + }; + like( exception { $will_croak->() }, qr/^Failed to convert packet to string/ ); +}; + done_testing(); diff --git a/t/rr.t b/t/rr.t index 9b7aa66..f9f0403 100644 --- a/t/rr.t +++ b/t/rr.t @@ -226,4 +226,12 @@ subtest 'SPF' => sub { is( $spf->spfdata, '"v=spf1 ip4:85.30.129.185/24 mx:mail.frobbit.se ip6:2a02:80:3ffe::0/64 ~all"' ); }; +subtest 'croak when given malformed CAA records' => sub { + my $will_croak = sub { + Zonemaster::LDNS::RR->new( + 'bad-caa.example. 3600 IN CAA \# 4 C0000202' ) + }; + like( exception { $will_croak->() }, qr/^Failed to convert RR to string/ ); +}; + done_testing; From deec8e9cfa8abecceb1497d30c69b9ea0d4fde38 Mon Sep 17 00:00:00 2001 From: Marc van der Wal Date: Thu, 1 Sep 2022 09:45:16 +0200 Subject: [PATCH 08/27] Fix unsafe string manipulations in XS code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix two instances of unsafe C string manipulations, vulnerable to null pointer dereferences and out-of-bounds accesses in edge cases. This was observed as segfaults in zonemaster-cli when attempting to process the following malformed resource record: bad-caa.example. IN CAA \# 4 C0000202 Zonemaster::LDNS::RR and Zonemaster::LDNS::Packet objects can be converted to a string (i.e. presentation format) with the string() method. Doing so triggers a call to the ldns_rr2str() and ldns_pkt2str() C functions respectively. However, when given some classes of malformed packets, ldns’s functions fail by returning NULL instead of a valid C string. Normally, these strings end with a newline, which is removed in the XS code before returning the result. But the removal of that newline character is attempted without checking for NULL pointers or empty strings. With this commit, Zonemaster::LDNS::RR->new() will now croak when given the aforementioned malformed resource record, and so will Zonemaster::LDNS::Packet->string() if it contains such a resource record. --- include/LDNS.h | 1 + src/LDNS.xs | 18 ++++++++++++++++-- src/assist.c | 17 +++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/include/LDNS.h b/include/LDNS.h index 9de985a..813b00e 100644 --- a/include/LDNS.h +++ b/include/LDNS.h @@ -108,6 +108,7 @@ typedef ldns_rr *Zonemaster__LDNS__RR__X25; SV *rr2sv(ldns_rr *rr); char *randomize_capitalization(char *in); +void strip_newline(char* in); #ifdef USE_ITHREADS void net_ldns_remember_resolver(SV *rv); diff --git a/src/LDNS.xs b/src/LDNS.xs index becb907..8f704c8 100644 --- a/src/LDNS.xs +++ b/src/LDNS.xs @@ -1233,7 +1233,14 @@ packet_string(obj) Zonemaster::LDNS::Packet obj; CODE: RETVAL = ldns_pkt2str(obj); - RETVAL[strlen(RETVAL)-1] = '\0'; + if(RETVAL == NULL || RETVAL[0] == '\0') + { + croak("Failed to convert packet to string"); + } + else + { + strip_newline(RETVAL); + } OUTPUT: RETVAL CLEANUP: @@ -1597,7 +1604,14 @@ rr_string(obj) Zonemaster::LDNS::RR obj; CODE: RETVAL = ldns_rr2str(obj); - RETVAL[strlen(RETVAL)-1] = '\0'; + if(RETVAL == NULL || RETVAL[0] == '\0') + { + croak("Failed to convert RR to string"); + } + else + { + strip_newline(RETVAL); + } OUTPUT: RETVAL CLEANUP: diff --git a/src/assist.c b/src/assist.c index 3f52792..413761e 100644 --- a/src/assist.c +++ b/src/assist.c @@ -228,3 +228,20 @@ rr2sv(ldns_rr *rr) return rr_sv; } + +void +strip_newline(char* in) +{ + size_t length; + + if (in == NULL || in[0] == '\0') + { + return; + } + + length = strlen(in); + if (in[length - 1] == '\n') + { + in[length - 1] = '\0'; + } +} From 65a7ce9e5d5faba1926b25bb2f173951b55fcd08 Mon Sep 17 00:00:00 2001 From: Marc van der Wal Date: Mon, 5 Sep 2022 07:45:07 +0200 Subject: [PATCH 09/27] =?UTF-8?q?Fix=20=E2=80=9Cbad=20CAA=E2=80=9D=20unit?= =?UTF-8?q?=20tests=20on=20single-threaded=20Perl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instantiation of a malformed CAA resource record is a guaranteed croak if and only if the Perl in use is compiled with support for interpreter threads (-DUSE_ITHREADS). If not, it won’t. So the unit test is modified to try to convert the bad CAA record back to presentation form, so that it does become a guaranteed croak. --- t/rr.t | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/t/rr.t b/t/rr.t index f9f0403..f0850fd 100644 --- a/t/rr.t +++ b/t/rr.t @@ -228,8 +228,11 @@ subtest 'SPF' => sub { subtest 'croak when given malformed CAA records' => sub { my $will_croak = sub { - Zonemaster::LDNS::RR->new( - 'bad-caa.example. 3600 IN CAA \# 4 C0000202' ) + # This will croak if LDNS.xs is compiled with -DUSE_ITHREADS + my $bad_caa = Zonemaster::LDNS::RR->new( + 'bad-caa.example. 3600 IN CAA \# 4 C0000202' ); + # This will always croak + $bad_caa->string(); }; like( exception { $will_croak->() }, qr/^Failed to convert RR to string/ ); }; From 4fdde0900fa27cb27444f99c959573b8d6267166 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Tue, 23 Aug 2022 19:00:34 +0200 Subject: [PATCH 10/27] Set and get EDNS option NSID for/from a packet --- src/LDNS.xs | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/LDNS.xs b/src/LDNS.xs index becb907..3806c10 100644 --- a/src/LDNS.xs +++ b/src/LDNS.xs @@ -1407,6 +1407,60 @@ packet_needs_edns(obj) OUTPUT: RETVAL +# +# Function: nsid +# -------------- +# Set the EDNS option NSID in the packet +# +void +packet_nsid(obj) + Zonemaster::LDNS::Packet obj; + CODE: + ldns_edns_option_list* edns_list; + ldns_edns_option* edns_opt; + + edns_list = ldns_edns_option_list_new(); + edns_opt = ldns_edns_new_from_data(LDNS_EDNS_NSID, 0, NULL); + if ( edns_list == NULL || edns_opt == NULL ) + croak("Could not allocate EDNS option"); + if ( ! ldns_edns_option_list_push(edns_list, edns_opt) ) + croak("Could not attach EDNS option NSID"); + ldns_pkt_set_edns_option_list(obj, edns_list); + +# +# Function: get_nsid +# ------------------ +# Get the EDNS option NSID if any from the packet +# +# returns: a bytes string (or undef if no NSID is found) +# +SV * +packet_get_nsid(obj) + Zonemaster::LDNS::Packet obj; + CODE: + ldns_edns_option_list* edns_list; + ldns_edns_option* edns_opt; + size_t count; + + edns_list = ldns_pkt_edns_get_option_list(obj); + if ( edns_list == NULL ) + XSRETURN_UNDEF; + + RETVAL = NULL; + count = ldns_edns_option_list_get_count(edns_list); + for ( int i=0; i Date: Wed, 24 Aug 2022 10:43:38 +0200 Subject: [PATCH 11/27] Enable NSID feature with LDNS version >= 1.8.2 --- Makefile.PL | 17 +++++++++++++++++ src/LDNS.xs | 12 ++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Makefile.PL b/Makefile.PL index 9f4fc66..90ae5ca 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -243,6 +243,23 @@ else { } } +# NSID feature requires LDNS version >= 1.8.2 +my $ldns_has_nsid = check_lib( + debug => $opt_debug, + lib => 'ldns', + header => 'ldns/util.h', + %{ $assert_lib_args{ldns} }, + function => 'if ( LDNS_REVISION >= ((1<<16)|(8<<8)|(2)) ) return 0; else return 1;' +); + +if ( $ldns_has_nsid ) { + print "Feature NSID enabled\n"; + cc_define '-DNSID_SUPPORT'; +} +else { + print "Feature NSID disabled\n"; +} + # Libidn diff --git a/src/LDNS.xs b/src/LDNS.xs index 3806c10..0a05899 100644 --- a/src/LDNS.xs +++ b/src/LDNS.xs @@ -1416,6 +1416,8 @@ void packet_nsid(obj) Zonemaster::LDNS::Packet obj; CODE: + { +#ifdef NSID_SUPPORT ldns_edns_option_list* edns_list; ldns_edns_option* edns_opt; @@ -1426,6 +1428,10 @@ packet_nsid(obj) if ( ! ldns_edns_option_list_push(edns_list, edns_opt) ) croak("Could not attach EDNS option NSID"); ldns_pkt_set_edns_option_list(obj, edns_list); +#else + croak("NSID not supported"); +#endif + } # # Function: get_nsid @@ -1438,6 +1444,8 @@ SV * packet_get_nsid(obj) Zonemaster::LDNS::Packet obj; CODE: + { +#ifdef NSID_SUPPORT ldns_edns_option_list* edns_list; ldns_edns_option* edns_opt; size_t count; @@ -1458,6 +1466,10 @@ packet_get_nsid(obj) } if ( RETVAL == NULL ) XSRETURN_UNDEF; +#else + croak("NSID not supported"); +#endif + } OUTPUT: RETVAL From 4e2d6da9847e404764d1d9d49406929e1f5dcbd8 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Wed, 28 Sep 2022 17:22:15 +0200 Subject: [PATCH 12/27] Update internal ldns to 1.8.3 --- MANIFEST | 2 ++ ldns | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/MANIFEST b/MANIFEST index 31d84c6..2209206 100644 --- a/MANIFEST +++ b/MANIFEST @@ -25,6 +25,7 @@ ldns/dnssec_sign.c ldns/dnssec_verify.c ldns/dnssec_zone.c ldns/duration.c +ldns/edns.c ldns/error.c ldns/higher.c ldns/host2str.c @@ -41,6 +42,7 @@ ldns/ldns/dnssec_sign.h ldns/ldns/dnssec_verify.h ldns/ldns/dnssec_zone.h ldns/ldns/duration.h +ldns/ldns/edns.h ldns/ldns/error.h ldns/ldns/higher.h ldns/ldns/host2str.h diff --git a/ldns b/ldns index 53bc575..173fbf3 160000 --- a/ldns +++ b/ldns @@ -1 +1 @@ -Subproject commit 53bc57512c19b11eebc403a4cb2bbf7295eb0db1 +Subproject commit 173fbf303518d060e0d2bdc0bbd1830c0ec8f21d From 4463084828de6d632e48fd143126901de52d9536 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Wed, 28 Sep 2022 18:07:51 +0200 Subject: [PATCH 13/27] Correctly look up for NSID support * internal LDNS is 1.8.3 so it supports NSID * external LDNS is unknown, a check is needed --- Makefile.PL | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index 90ae5ca..1a066bd 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -213,12 +213,15 @@ else { } -# LDNS +# LDNS and NSID + +my $ldns_has_nsid; if ( $opt_internal_ldns ) { print "Feature internal ldns enabled\n"; cc_libs '-Lldns/lib'; cc_include_paths 'ldns'; + $ldns_has_nsid = 1; } else { print "Feature internal ldns disabled\n"; @@ -241,16 +244,16 @@ else { function => 'if(LDNS_ED25519) return 0; else return 1;' ); } -} -# NSID feature requires LDNS version >= 1.8.2 -my $ldns_has_nsid = check_lib( - debug => $opt_debug, - lib => 'ldns', - header => 'ldns/util.h', - %{ $assert_lib_args{ldns} }, - function => 'if ( LDNS_REVISION >= ((1<<16)|(8<<8)|(2)) ) return 0; else return 1;' -); + # NSID feature requires LDNS version >= 1.8.2 + $ldns_has_nsid = check_lib( + debug => $opt_debug, + lib => 'ldns', + header => 'ldns/util.h', + %{ $assert_lib_args{ldns} }, + function => 'if ( LDNS_REVISION >= ((1<<16)|(8<<8)|(2)) ) return 0; else return 1;' + ); +} if ( $ldns_has_nsid ) { print "Feature NSID enabled\n"; From 56ed5438ebe01be1b83b15f7c79177e8015580e0 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Wed, 28 Sep 2022 18:14:19 +0200 Subject: [PATCH 14/27] Unit test for NSID support --- MANIFEST | 1 + t/nsid.t | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 t/nsid.t diff --git a/MANIFEST b/MANIFEST index 2209206..6555fc5 100644 --- a/MANIFEST +++ b/MANIFEST @@ -182,6 +182,7 @@ t/example.org t/idn.t t/load_zonefile.t t/netldns.t +t/nsid.t t/packet.t t/regression.t t/resolver.t diff --git a/t/nsid.t b/t/nsid.t new file mode 100644 index 0000000..f4a5478 --- /dev/null +++ b/t/nsid.t @@ -0,0 +1,22 @@ +use strict; +use warnings; + +use Test::More; +use Zonemaster::LDNS; + +SKIP: { + skip 'no network', 1 unless $ENV{TEST_WITH_NETWORK}; + + my $host = '192.134.4.1'; #ns1.nic.fr with nsid: ns1.th3.nic.fr + my $expected_nsid = "ns1.th3.nic.fr"; + + my $pkt = Zonemaster::LDNS::Packet->new('domain.example'); + $pkt->nsid; # set the NSID EDNS option + my $res = Zonemaster::LDNS->new($host)->query_with_pkt($pkt); + + my $nsid = $res->get_nsid(); + + is( $nsid, $expected_nsid, 'Correct NSID' ); +}; + +done_testing(); From a8ccdb73a61d0b64fb3f715985d4932f68754ad2 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Tue, 4 Oct 2022 19:36:39 +0200 Subject: [PATCH 15/27] Don't overwrite already defined EDNS options --- src/LDNS.xs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/LDNS.xs b/src/LDNS.xs index 0a05899..41606b0 100644 --- a/src/LDNS.xs +++ b/src/LDNS.xs @@ -1421,7 +1421,11 @@ packet_nsid(obj) ldns_edns_option_list* edns_list; ldns_edns_option* edns_opt; - edns_list = ldns_edns_option_list_new(); + edns_list = ldns_pkt_edns_get_option_list(obj); + + if ( !edns_list ) + edns_list = ldns_edns_option_list_new(); + edns_opt = ldns_edns_new_from_data(LDNS_EDNS_NSID, 0, NULL); if ( edns_list == NULL || edns_opt == NULL ) croak("Could not allocate EDNS option"); From ef0a666ee5b71ce029c61fc683bfbfeadd7d9f02 Mon Sep 17 00:00:00 2001 From: Marc van der Wal Date: Thu, 6 Oct 2022 14:09:44 +0200 Subject: [PATCH 16/27] Improve access to text data in TXT records So far, there has been no real elegant way of accessing the data in DNS TXT records. The only existing method, txtdata(), is implemented in XS code and has several issues. Firstly, it only returns the first string of the TXT record. Secondly, it returns that string in presentation format, that is, it returns a string which itself has surrounding quotes and contains decimal escapes for non-printable characters. This incorrect implementation is replaced with one in pure Perl. Normally, the only correct abstraction for TXT resource records is a list of strings. But for some use cases, such as SPF, DKIM and DMARC, the TXT record data ought to be treated as a single long string, which is the concatenation of all the strings in the TXT resource record data, without adding any spaces between consecutive strings. To my knowledge, there is no need to access the actual list of strings in the resource record data. This function could easily be made context-sensitive (e.g. by returning the list of strings in list context) if need be. This commit is also an excellent opportunity to rewrite the unit test for TXT resource records. The previous version needed Internet connectivity, but this new version can be run offline. --- lib/Zonemaster/LDNS/RR/TXT.pm | 14 +++++++++++++- src/LDNS.xs | 13 ------------- t/rr.t | 22 +++++++++++----------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/lib/Zonemaster/LDNS/RR/TXT.pm b/lib/Zonemaster/LDNS/RR/TXT.pm index 1df7069..27b694a 100644 --- a/lib/Zonemaster/LDNS/RR/TXT.pm +++ b/lib/Zonemaster/LDNS/RR/TXT.pm @@ -5,6 +5,12 @@ use warnings; use parent 'Zonemaster::LDNS::RR'; +sub txtdata() { + my ($rr) = @_; + + return join( "", map { substr($rr->rdf($_ - 1), 1) } 1..$rr->rd_count() ); +} + 1; =head1 NAME @@ -21,6 +27,12 @@ A subclass of L, so it has all the methods of that class a =item txtdata() -Returns the text data. +Returns the concatenation of all the strings composing the data of the resource record. + +For example, if a TXT resource record has the following presentation format: + + txt.test.example. 3600 IN TXT "I " "am " "split up in " "lit" "tle pieces" + +then C returns the string C<"I am split up in little pieces">. =back diff --git a/src/LDNS.xs b/src/LDNS.xs index becb907..2341a3d 100644 --- a/src/LDNS.xs +++ b/src/LDNS.xs @@ -2366,19 +2366,6 @@ rr_cname_cname(obj) CLEANUP: free(RETVAL); - -MODULE = Zonemaster::LDNS PACKAGE = Zonemaster::LDNS::RR::TXT PREFIX=rr_txt_ - -char * -rr_txt_txtdata(obj) - Zonemaster::LDNS::RR::TXT obj; - CODE: - RETVAL = D_STRING(obj,0); - OUTPUT: - RETVAL - CLEANUP: - free(RETVAL); - MODULE = Zonemaster::LDNS PACKAGE = Zonemaster::LDNS::RR::SPF PREFIX=rr_spf_ char * diff --git a/t/rr.t b/t/rr.t index 9b7aa66..a442386 100644 --- a/t/rr.t +++ b/t/rr.t @@ -77,18 +77,18 @@ subtest 'AAAA' => sub { }; subtest 'TXT' => sub { - SKIP: { - skip 'no network', 1 unless $ENV{TEST_WITH_NETWORK}; - - my $se = Zonemaster::LDNS->new( '192.36.144.107' ); - my $pt = $se->query( 'se', 'TXT' ); - plan skip_all => 'No response, cannot test' if not $pt; - - foreach my $rr ( $pt->answer ) { - isa_ok( $rr, 'Zonemaster::LDNS::RR::TXT' ); - like( $rr->txtdata, qr/^"SE zone update: / ); - } + my @data = ( + q{txt.test. 3600 IN TXT "Handling TXT RRs can be challenging"}, + q{txt.test. 3600 IN TXT "because " "the data can " "be spl" "it up like " "this!"} + ); + my @rrs = map { Zonemaster::LDNS::RR->new($_) } @data; + + foreach my $rr ( @rrs ) { + isa_ok( $rr, 'Zonemaster::LDNS::RR::TXT' ); } + + is( $rrs[0]->txtdata(), q{Handling TXT RRs can be challenging} ); + is( $rrs[1]->txtdata(), q{because the data can be split up like this!} ); }; subtest 'DNSKEY' => sub { From 8b8dd0ba1af6330cdd6dff46df02c0e6984a0761 Mon Sep 17 00:00:00 2001 From: Marc van der Wal Date: Thu, 6 Oct 2022 14:39:33 +0200 Subject: [PATCH 17/27] Improve access to data in SPF records SPF resource records are, in essence, TXT resource records with a different type identifier. The only real difference between SPF and TXT resource records lies in their uses: TXT is more generic, where SPF was meant for publishing Sender Policy Framework policies before being deprecated. The Zonemaster::LDNS::RR::SPF module suffered from the same problem as its TXT counterpart, i.e. the spfdata() method only returns the first string, in presentation format. For parsing actual SPF policies, however, the behavior of the spfdata() method is both not very useful as well as incorrect: RFC 7208 states that the SPF policy is the concatenation of *all* strings in a single TXT (or SPF) resource record. So like with the txtdata() method in the TXT package, we entirely replace the spfdata() method with a correct and pure-Perl variant. --- lib/Zonemaster/LDNS/RR/SPF.pm | 14 +++++++++++++- src/LDNS.xs | 12 ------------ t/rr.t | 17 +++++++++++++---- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/lib/Zonemaster/LDNS/RR/SPF.pm b/lib/Zonemaster/LDNS/RR/SPF.pm index 48e4fec..9ff290f 100644 --- a/lib/Zonemaster/LDNS/RR/SPF.pm +++ b/lib/Zonemaster/LDNS/RR/SPF.pm @@ -5,6 +5,12 @@ use warnings; use parent 'Zonemaster::LDNS::RR'; +sub spfdata() { + my ($rr) = @_; + + return join( "", map { substr($rr->rdf($_ - 1), 1) } 1..$rr->rd_count() ); +} + 1; =head1 NAME @@ -21,6 +27,12 @@ A subclass of L, so it has all the methods of that class a =item spfdata() -Returns the SPF string. +Returns the concatenation of all the strings composing the data of the resource record. + +For example, if an SPF resource record has the following presentation format: + + test.example. 3600 IN SPF "v=spf1 " "mx " "a " "-all" + +then C returns the string C<"v=spf1 mx a -all">. =back diff --git a/src/LDNS.xs b/src/LDNS.xs index 2341a3d..bf051ff 100644 --- a/src/LDNS.xs +++ b/src/LDNS.xs @@ -2366,18 +2366,6 @@ rr_cname_cname(obj) CLEANUP: free(RETVAL); -MODULE = Zonemaster::LDNS PACKAGE = Zonemaster::LDNS::RR::SPF PREFIX=rr_spf_ - -char * -rr_spf_spfdata(obj) - Zonemaster::LDNS::RR::SPF obj; - CODE: - RETVAL = D_STRING(obj,0); - OUTPUT: - RETVAL - CLEANUP: - free(RETVAL); - MODULE = Zonemaster::LDNS PACKAGE = Zonemaster::LDNS::RR::KEY PREFIX=rr_key_ U16 diff --git a/t/rr.t b/t/rr.t index a442386..fdd2bc8 100644 --- a/t/rr.t +++ b/t/rr.t @@ -220,10 +220,19 @@ subtest 'SRV' => sub { }; subtest 'SPF' => sub { - my $spf = Zonemaster::LDNS::RR->new( - 'frobbit.se. 1127 IN SPF "v=spf1 ip4:85.30.129.185/24 mx:mail.frobbit.se ip6:2a02:80:3ffe::0/64 ~all"' ); - isa_ok( $spf, 'Zonemaster::LDNS::RR::SPF' ); - is( $spf->spfdata, '"v=spf1 ip4:85.30.129.185/24 mx:mail.frobbit.se ip6:2a02:80:3ffe::0/64 ~all"' ); + my @data = ( + q{frobbit.se. 1127 IN SPF "v=spf1 ip4:85.30.129.185/24 mx:mail.frobbit.se ip6:2a02:80:3ffe::0/64 ~all"}, + q{spf.example. 3600 IN SPF "v=spf1 " "ip4:192.0.2.25/24 " "mx:mail.spf.example " "ip6:2001:db8::25/64 -all"} + ); + + my @rr = map { Zonemaster::LDNS::RR->new($_) } @data; + for my $spf (@rr) { + isa_ok( $spf, 'Zonemaster::LDNS::RR::SPF' ); + } + + is( $rr[0]->spfdata(), 'v=spf1 ip4:85.30.129.185/24 mx:mail.frobbit.se ip6:2a02:80:3ffe::0/64 ~all' ); + is( $rr[1]->spfdata(), 'v=spf1 ip4:192.0.2.25/24 mx:mail.spf.example ip6:2001:db8::25/64 -all' ); + }; done_testing; From 7535a41d35e7d8ebfa4ba603b00ac89dfe2dd0a0 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Mon, 17 Oct 2022 09:18:58 +0200 Subject: [PATCH 18/27] Missing files in MANIFEST from libldns --- MANIFEST | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MANIFEST b/MANIFEST index 6555fc5..3d27a82 100644 --- a/MANIFEST +++ b/MANIFEST @@ -11,6 +11,8 @@ inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm inc/Module/Install/XSUtil.pm include/LDNS.h +ldns/.github/FUNDING.yml +ldns/.github/workflows/testsuite.yml ldns/buffer.c ldns/compat/b64_ntop.c ldns/compat/b64_pton.c @@ -66,6 +68,7 @@ ldns/ldns/update.h ldns/ldns/util.h.in ldns/ldns/wire2host.h ldns/ldns/zone.h +ldns/libdns.doxygen.in ldns/LICENSE ldns/ltmain.sh ldns/Makefile.in @@ -77,6 +80,7 @@ ldns/parse.c ldns/radix.c ldns/rbtree.c ldns/rdata.c +ldns/README-Travis.md ldns/resolver.c ldns/rr.c ldns/rr_functions.c From 8fc702f74608fccb715763bca5512a5587438e70 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Thu, 20 Oct 2022 16:37:35 +0200 Subject: [PATCH 19/27] Fix libldns reconfiguration on update Use prerequisites to check for submodule existence and rebuild it on change (based on Changelog file updates). --- Makefile.PL | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index 9f4fc66..c4a557c 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -352,12 +352,14 @@ ldns/.libs/libldns.a: ldns/configure ./configure CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" $(CONFIGURE_FLAGS) ;\ make lib -ldns/configure: +ldns/configure: ldns/Changelog + cd ldns ; libtoolize -ci + cd ldns ; autoreconf -fi + +ldns/Changelog: git submodule init git submodule sync git submodule update - cd ldns ; libtoolize -ci - cd ldns ; autoreconf -fi END_INTERNAL_LDNS From 0ff8d4239f920e6195b8810096f0b530b8f32e06 Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Thu, 20 Oct 2022 16:43:51 +0200 Subject: [PATCH 20/27] Keep ldns changelog file The file would be installed, and ease libldns review. --- MANIFEST | 1 + MANIFEST.SKIP | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST b/MANIFEST index 31d84c6..459c4f9 100644 --- a/MANIFEST +++ b/MANIFEST @@ -12,6 +12,7 @@ inc/Module/Install/WriteAll.pm inc/Module/Install/XSUtil.pm include/LDNS.h ldns/buffer.c +ldns/Changelog ldns/compat/b64_ntop.c ldns/compat/b64_pton.c ldns/compat/strlcpy.c diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP index f70a36d..e32c894 100644 --- a/MANIFEST.SKIP +++ b/MANIFEST.SKIP @@ -16,7 +16,6 @@ \.ac$ # Avoid ldns files we don't need -^ldns/Changelog$ ^ldns/README$ ^ldns/README\. ^ldns/\.libs/ From e475dceb4775f47f57eea278cb99d2fea365d745 Mon Sep 17 00:00:00 2001 From: Mats Dufberg Date: Sat, 26 Nov 2022 18:54:44 +0100 Subject: [PATCH 21/27] Corrects the license statement --- lib/Zonemaster/LDNS.pm | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/Zonemaster/LDNS.pm b/lib/Zonemaster/LDNS.pm index 1bea10b..4c6c439 100644 --- a/lib/Zonemaster/LDNS.pm +++ b/lib/Zonemaster/LDNS.pm @@ -212,11 +212,7 @@ Calle Dybedahl =head1 LICENSE -This is free software, licensed under: - -The (three-clause) BSD License - -The full text of the license can be found in the -F file included with this distribution. +This is free software. The full text of the license can +be found in the F file included with this distribution. =cut From 34796e48eb76332dae6af82ffd592b2dd983e766 Mon Sep 17 00:00:00 2001 From: Mats Dufberg Date: Sun, 27 Nov 2022 15:06:12 +0100 Subject: [PATCH 22/27] Adjustss the license statement --- lib/Zonemaster/LDNS.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Zonemaster/LDNS.pm b/lib/Zonemaster/LDNS.pm index 4c6c439..6206478 100644 --- a/lib/Zonemaster/LDNS.pm +++ b/lib/Zonemaster/LDNS.pm @@ -212,7 +212,7 @@ Calle Dybedahl =head1 LICENSE -This is free software. The full text of the license can +This is free software under a 2-clause BSD license. The full text of the license can be found in the F file included with this distribution. =cut From c47fedf914141b83c0f18945acf00a286c70068b Mon Sep 17 00:00:00 2001 From: Mats Dufberg Date: Sun, 27 Nov 2022 15:43:53 +0100 Subject: [PATCH 23/27] Adds license reference to README --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d27c9e..addd3e4 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ * [Custom LDNS] * [Custom Libidn] * [Debug] - +* [License](#license) ## Introduction @@ -224,6 +224,11 @@ Enabled with `--debug`. Gives a more verbose output. +## License + +This is free software under a 2-clause BSD license. The full text of the license can +be found in the [LICENSE](LICENSE) file included in this respository. + [Custom LDNS]: #custom-ldns [Custom Libidn]: #custom-libidn From 5aab2b460df83ee9a5627b77343a4bdb4af3cfcd Mon Sep 17 00:00:00 2001 From: Alexandre Pion Date: Wed, 7 Dec 2022 14:06:58 +0100 Subject: [PATCH 24/27] Fix build --- Makefile.PL | 2 +- src/LDNS.xs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index f64f094..ea715c2 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -343,7 +343,7 @@ END_OPENSSL_MAKE my $openssl_flags = < Date: Wed, 7 Dec 2022 16:57:27 +0100 Subject: [PATCH 25/27] use internal LDNS for docker image --- Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2d5a928..8f19074 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,6 @@ FROM alpine:3.14 as build RUN apk add --no-cache \ # Compile-time dependencies build-base \ - ldns-dev \ libidn2-dev \ make \ openssl-dev \ @@ -20,7 +19,7 @@ ARG version COPY ./Zonemaster-LDNS-${version}.tar.gz ./Zonemaster-LDNS-${version}.tar.gz -RUN cpanm --notest --no-wget --configure-args="--no-internal-ldns" \ +RUN cpanm --notest --no-wget \ ./Zonemaster-LDNS-${version}.tar.gz FROM alpine:3.14 @@ -31,6 +30,5 @@ COPY --from=build /usr/local/lib/perl5/site_perl/Zonemaster /usr/local/lib/perl5 RUN apk add --no-cache \ # Run-time dependencies - ldns \ libidn2 \ perl From 48a2b124340115ff20d6a2503995177bc71ae0af Mon Sep 17 00:00:00 2001 From: Mats Dufberg Date: Tue, 13 Dec 2022 14:43:46 +0100 Subject: [PATCH 26/27] Updates for release v2022.2 --- Changes | 23 +++++++++++++++++++++++ lib/Zonemaster/LDNS.pm | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 972d85f..d1579d7 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,28 @@ Release history for Zonemaster component Zonemaster-LDNS +3.0.0 2022-12-19 + + [Breaking change] + - Improves access to text data in TXT and SPF resource records + (#157, #155) + + [Features] + - Uses internal LDNS for docker image (#162) + - Adds support for NSID option (#151) + - Updates internal LDNS to 1.8.3 (#151, #143) + - Adds options to build with Libidn and LDNS in custom locations + (#152) + + [Fixes] + - Fixes a bug when building LDNS with link to OpenSSL (#161) + - Corrects the license statement in LDNS.pm (#159) + - Fixes unsafe string manipulations in XS code (#153, #149) + - Automatically reconfigures internal libldns on "ldns/Changelog" + updates (#158) + - URL fragments referring to internal headings in lowercase + (#154) + + 2.2.2 2022-06-09 [Features] diff --git a/lib/Zonemaster/LDNS.pm b/lib/Zonemaster/LDNS.pm index 6206478..a9b88e8 100644 --- a/lib/Zonemaster/LDNS.pm +++ b/lib/Zonemaster/LDNS.pm @@ -2,7 +2,7 @@ package Zonemaster::LDNS; use 5.014; -our $VERSION = '2.2.2'; +our $VERSION = '3.0.0'; use parent 'Exporter'; our @EXPORT_OK = qw[to_idn has_idn ldns_version load_zonefile]; From f18058b40b8950a0701f984746bfa41ea2e21f66 Mon Sep 17 00:00:00 2001 From: Mats Dufberg Date: Mon, 19 Dec 2022 08:16:10 +0100 Subject: [PATCH 27/27] Update_master_to_state_of_develop --- Changes | 23 ++++ Dockerfile | 4 +- MANIFEST | 8 ++ MANIFEST.SKIP | 1 - Makefile.PL | 209 ++++++++++++++++++++++++++-------- README.md | 48 +++++++- include/LDNS.h | 1 + ldns | 2 +- lib/Zonemaster/LDNS.pm | 10 +- lib/Zonemaster/LDNS/RR/SPF.pm | 14 ++- lib/Zonemaster/LDNS/RR/TXT.pm | 14 ++- src/LDNS.xs | 113 +++++++++++++----- src/assist.c | 17 +++ t/nsid.t | 22 ++++ t/packet.t | 31 +++++ t/rr.t | 50 +++++--- 16 files changed, 459 insertions(+), 108 deletions(-) create mode 100644 t/nsid.t diff --git a/Changes b/Changes index 972d85f..d1579d7 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,28 @@ Release history for Zonemaster component Zonemaster-LDNS +3.0.0 2022-12-19 + + [Breaking change] + - Improves access to text data in TXT and SPF resource records + (#157, #155) + + [Features] + - Uses internal LDNS for docker image (#162) + - Adds support for NSID option (#151) + - Updates internal LDNS to 1.8.3 (#151, #143) + - Adds options to build with Libidn and LDNS in custom locations + (#152) + + [Fixes] + - Fixes a bug when building LDNS with link to OpenSSL (#161) + - Corrects the license statement in LDNS.pm (#159) + - Fixes unsafe string manipulations in XS code (#153, #149) + - Automatically reconfigures internal libldns on "ldns/Changelog" + updates (#158) + - URL fragments referring to internal headings in lowercase + (#154) + + 2.2.2 2022-06-09 [Features] diff --git a/Dockerfile b/Dockerfile index 2d5a928..8f19074 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,6 @@ FROM alpine:3.14 as build RUN apk add --no-cache \ # Compile-time dependencies build-base \ - ldns-dev \ libidn2-dev \ make \ openssl-dev \ @@ -20,7 +19,7 @@ ARG version COPY ./Zonemaster-LDNS-${version}.tar.gz ./Zonemaster-LDNS-${version}.tar.gz -RUN cpanm --notest --no-wget --configure-args="--no-internal-ldns" \ +RUN cpanm --notest --no-wget \ ./Zonemaster-LDNS-${version}.tar.gz FROM alpine:3.14 @@ -31,6 +30,5 @@ COPY --from=build /usr/local/lib/perl5/site_perl/Zonemaster /usr/local/lib/perl5 RUN apk add --no-cache \ # Run-time dependencies - ldns \ libidn2 \ perl diff --git a/MANIFEST b/MANIFEST index 31d84c6..3173041 100644 --- a/MANIFEST +++ b/MANIFEST @@ -11,7 +11,10 @@ inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm inc/Module/Install/XSUtil.pm include/LDNS.h +ldns/.github/FUNDING.yml +ldns/.github/workflows/testsuite.yml ldns/buffer.c +ldns/Changelog ldns/compat/b64_ntop.c ldns/compat/b64_pton.c ldns/compat/strlcpy.c @@ -25,6 +28,7 @@ ldns/dnssec_sign.c ldns/dnssec_verify.c ldns/dnssec_zone.c ldns/duration.c +ldns/edns.c ldns/error.c ldns/higher.c ldns/host2str.c @@ -41,6 +45,7 @@ ldns/ldns/dnssec_sign.h ldns/ldns/dnssec_verify.h ldns/ldns/dnssec_zone.h ldns/ldns/duration.h +ldns/ldns/edns.h ldns/ldns/error.h ldns/ldns/higher.h ldns/ldns/host2str.h @@ -64,6 +69,7 @@ ldns/ldns/update.h ldns/ldns/util.h.in ldns/ldns/wire2host.h ldns/ldns/zone.h +ldns/libdns.doxygen.in ldns/LICENSE ldns/ltmain.sh ldns/Makefile.in @@ -75,6 +81,7 @@ ldns/parse.c ldns/radix.c ldns/rbtree.c ldns/rdata.c +ldns/README-Travis.md ldns/resolver.c ldns/rr.c ldns/rr_functions.c @@ -180,6 +187,7 @@ t/example.org t/idn.t t/load_zonefile.t t/netldns.t +t/nsid.t t/packet.t t/regression.t t/resolver.t diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP index f70a36d..e32c894 100644 --- a/MANIFEST.SKIP +++ b/MANIFEST.SKIP @@ -16,7 +16,6 @@ \.ac$ # Avoid ldns files we don't need -^ldns/Changelog$ ^ldns/README$ ^ldns/README\. ^ldns/\.libs/ diff --git a/Makefile.PL b/Makefile.PL index cf5c342..ea715c2 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -58,6 +58,26 @@ The PATH is passed to the LDNS compiler via the CFLAGS variable. Search for OpenSSL library in PATH. The PATH is passed to the LDNS compiler via the LDFLAGS variable. +=item --libidn-inc=PATH + +Search for Libidn include in PATH. + +=item --libidn-lib=PATH + +Search for Libidn library in PATH. + +=item --ldns-inc=PATH + +Search for LDNS include in PATH. + +=item --ldns-lib=PATH + +Search for LDNS library in PATH. + +=item --debug + +Enable debug mode, more verbose output. + =back =cut @@ -66,17 +86,36 @@ my $opt_ed25519 = 1; my $opt_idn = 1; my $opt_internal_ldns = 1; my $opt_randomize = 0; -my $opt_prefix_openssl = ""; -my $opt_openssl_inc = ""; -my $opt_openssl_lib = ""; +my $opt_debug = 0; +my $opt_assets = { + openssl => { + prefix => "", + inc => "", + lib => "" + }, + ldns => { + inc => "", + lib => "" + }, + libidn => { + inc => "", + lib => "" + } +}; + GetOptions( 'ed25519!' => \$opt_ed25519, 'idn!' => \$opt_idn, 'internal-ldns!' => \$opt_internal_ldns, 'randomize!' => \$opt_randomize, - 'prefix-openssl=s' => \$opt_prefix_openssl, - 'openssl-inc=s' => \$opt_openssl_inc, - 'openssl-lib=s' => \$opt_openssl_lib, + 'debug!' => \$opt_debug, + 'prefix-openssl=s' => \$$opt_assets{openssl}{prefix}, + 'openssl-inc=s' => \$$opt_assets{openssl}{inc}, + 'openssl-lib=s' => \$$opt_assets{openssl}{lib}, + 'libidn-inc=s' => \$$opt_assets{libidn}{inc}, + 'libidn-lib=s' => \$$opt_assets{libidn}{lib}, + 'ldns-inc=s' => \$$opt_assets{ldns}{inc}, + 'ldns-lib=s' => \$$opt_assets{ldns}{lib}, ); configure_requires 'Devel::CheckLib'; @@ -91,52 +130,82 @@ cc_include_paths 'include'; cc_src_paths 'src'; -# OpenSSL - -my %assert_lib_args_openssl; -my $custom_openssl = ( $opt_prefix_openssl or $opt_openssl_inc or $opt_openssl_lib ); -if ( $custom_openssl ) { - my $openssl_incpath = ""; - my $openssl_libpath = ""; +my %assert_lib_args = ( + openssl => {}, + libidn => {}, + ldns => {} +); - if ( $opt_prefix_openssl ) { - print "Custom prefix for OpenSSL: $opt_prefix_openssl\n"; - $openssl_incpath = "$opt_prefix_openssl/include"; - $openssl_libpath = "$opt_prefix_openssl/lib"; +sub custom_assets +{ + my ( $href ) = @_; + # $href = { key => "openssl", lib => "crypto", name => "OpenSSL" } + + my $key = $$href{key}; + my $name = $$href{name}; + my $lib = $$href{lib}; + + my $input_prefix = $$opt_assets{$key}{prefix}; + my $input_inc = $$opt_assets{$key}{inc}; + my $input_lib = $$opt_assets{$key}{lib}; + + my $custom_lib = ( $input_prefix or $input_inc or $input_lib ); + if ( $custom_lib ) { + my $incpath = ""; + my $libpath = ""; + + if ( $input_prefix ) { + print "Custom prefix for $name: $input_prefix\n"; + $incpath = "$input_prefix/include"; + $libpath = "$input_prefix/lib"; + } + + if ( $input_inc ) { + print "Custom include directory for $name: $input_inc\n"; + $incpath = "$input_inc"; + } + + if ( $input_lib ) { + print "Custom library directory for $name: $input_lib\n"; + $libpath = "$input_lib"; + } + + cc_include_paths "$incpath"; + cc_libs "-L$libpath", "$lib"; + + $assert_lib_args{$key}{incpath} = "$incpath"; + $assert_lib_args{$key}{libpath} = "$libpath"; } - - if ( $opt_openssl_inc ) { - print "Custom include directory for OpenSSL: $opt_openssl_inc\n"; - $openssl_incpath = "$opt_openssl_inc"; + else { + cc_libs "$lib"; } +} - if ( $opt_openssl_lib ) { - print "Custom library directory for OpenSSL: $opt_openssl_lib\n"; - $openssl_libpath = "$opt_openssl_lib"; - } +# OpenSSL - cc_include_paths "$openssl_incpath"; - cc_libs "-L$openssl_libpath", "crypto"; - $assert_lib_args_openssl{incpath} = "$openssl_incpath"; - $assert_lib_args_openssl{libpath} = "$openssl_libpath"; -} -else { - cc_libs 'crypto'; -} +custom_assets( + { + name => "OpenSSL", + lib => "crypto", + key => "openssl" + } +); cc_assert_lib( + debug => $opt_debug, lib => 'crypto', header => 'openssl/crypto.h', function => 'if(SSLeay()) return 0; else return 1;', - %assert_lib_args_openssl, + %{ $assert_lib_args{openssl} }, ); if ( $opt_ed25519 ) { print "Feature Ed25519 enabled\n"; cc_assert_lib( + debug => $opt_debug, lib => 'crypto', header => 'openssl/evp.h', function => 'EVP_PKEY_ED25519; return 0;', - %assert_lib_args_openssl, + %{ $assert_lib_args{openssl} }, ); } else { @@ -144,37 +213,77 @@ else { } -# LDNS +# LDNS and NSID + +my $ldns_has_nsid; if ( $opt_internal_ldns ) { print "Feature internal ldns enabled\n"; cc_libs '-Lldns/lib'; cc_include_paths 'ldns'; + $ldns_has_nsid = 1; } else { print "Feature internal ldns disabled\n"; - cc_libs 'ldns'; + + custom_assets( + { + name => "LDNS", + lib => "ldns", + key => "ldns" + } + ); + if ( $opt_ed25519 ) { cc_assert_lib( + debug => $opt_debug, lib => 'ldns', header => 'ldns/ldns.h', + %{ $assert_lib_args{ldns} }, ccflags => '-DUSE_ED25519', function => 'if(LDNS_ED25519) return 0; else return 1;' ); } + + # NSID feature requires LDNS version >= 1.8.2 + $ldns_has_nsid = check_lib( + debug => $opt_debug, + lib => 'ldns', + header => 'ldns/util.h', + %{ $assert_lib_args{ldns} }, + function => 'if ( LDNS_REVISION >= ((1<<16)|(8<<8)|(2)) ) return 0; else return 1;' + ); } +if ( $ldns_has_nsid ) { + print "Feature NSID enabled\n"; + cc_define '-DNSID_SUPPORT'; +} +else { + print "Feature NSID disabled\n"; +} -# IDN + +# Libidn if ( $opt_idn ) { print "Feature idn enabled\n"; + + custom_assets( + { + name => "Libidn", + lib => "idn2", + key => "libidn" + } + ); + check_lib_or_exit( + debug => $opt_debug, lib => 'idn2', header => 'idn2.h', - function => - 'return IDN2_OK;'); - cc_libs 'idn2'; + %{ $assert_lib_args{libidn} }, + function => 'return IDN2_OK;' + ); cc_define '-DWE_CAN_HAZ_IDN'; } else { @@ -228,14 +337,14 @@ END_CONFIGURE_FLAGS my $openssl_make = < Requires [Internal LDNS] to be disabled. + + +### Custom Libidn + +Disabled by default. +Enabled with `--libidn-inc=/path/to/libidn_inc` or +`--libidn-lib=/path/to/ldns_lib`. + +Enabling this makes the build tools look for Libidn in a non-standard place. + +> Requires [IDN] to be enabled. + + +### Debug + +Disabled by default. +Enabled with `--debug`. + +Gives a more verbose output. + +## License + +This is free software under a 2-clause BSD license. The full text of the license can +be found in the [LICENSE](LICENSE) file included in this respository. + + +[Custom LDNS]: #custom-ldns +[Custom Libidn]: #custom-libidn +[Custom OpenSSL]: #custom-openssl +[Debug]: #debug [DNS::LDNS]: http://search.cpan.org/~erikoest/DNS-LDNS/ [Docker Hub]: https://hub.docker.com/u/zonemaster [Docker Image Creation]: https://github.com/zonemaster/zonemaster/blob/master/docs/internal-documentation/maintenance/ReleaseProcess-create-docker-image.md diff --git a/include/LDNS.h b/include/LDNS.h index 9de985a..813b00e 100644 --- a/include/LDNS.h +++ b/include/LDNS.h @@ -108,6 +108,7 @@ typedef ldns_rr *Zonemaster__LDNS__RR__X25; SV *rr2sv(ldns_rr *rr); char *randomize_capitalization(char *in); +void strip_newline(char* in); #ifdef USE_ITHREADS void net_ldns_remember_resolver(SV *rv); diff --git a/ldns b/ldns index 53bc575..173fbf3 160000 --- a/ldns +++ b/ldns @@ -1 +1 @@ -Subproject commit 53bc57512c19b11eebc403a4cb2bbf7295eb0db1 +Subproject commit 173fbf303518d060e0d2bdc0bbd1830c0ec8f21d diff --git a/lib/Zonemaster/LDNS.pm b/lib/Zonemaster/LDNS.pm index 1bea10b..a9b88e8 100644 --- a/lib/Zonemaster/LDNS.pm +++ b/lib/Zonemaster/LDNS.pm @@ -2,7 +2,7 @@ package Zonemaster::LDNS; use 5.014; -our $VERSION = '2.2.2'; +our $VERSION = '3.0.0'; use parent 'Exporter'; our @EXPORT_OK = qw[to_idn has_idn ldns_version load_zonefile]; @@ -212,11 +212,7 @@ Calle Dybedahl =head1 LICENSE -This is free software, licensed under: - -The (three-clause) BSD License - -The full text of the license can be found in the -F file included with this distribution. +This is free software under a 2-clause BSD license. The full text of the license can +be found in the F file included with this distribution. =cut diff --git a/lib/Zonemaster/LDNS/RR/SPF.pm b/lib/Zonemaster/LDNS/RR/SPF.pm index 48e4fec..9ff290f 100644 --- a/lib/Zonemaster/LDNS/RR/SPF.pm +++ b/lib/Zonemaster/LDNS/RR/SPF.pm @@ -5,6 +5,12 @@ use warnings; use parent 'Zonemaster::LDNS::RR'; +sub spfdata() { + my ($rr) = @_; + + return join( "", map { substr($rr->rdf($_ - 1), 1) } 1..$rr->rd_count() ); +} + 1; =head1 NAME @@ -21,6 +27,12 @@ A subclass of L, so it has all the methods of that class a =item spfdata() -Returns the SPF string. +Returns the concatenation of all the strings composing the data of the resource record. + +For example, if an SPF resource record has the following presentation format: + + test.example. 3600 IN SPF "v=spf1 " "mx " "a " "-all" + +then C returns the string C<"v=spf1 mx a -all">. =back diff --git a/lib/Zonemaster/LDNS/RR/TXT.pm b/lib/Zonemaster/LDNS/RR/TXT.pm index 1df7069..27b694a 100644 --- a/lib/Zonemaster/LDNS/RR/TXT.pm +++ b/lib/Zonemaster/LDNS/RR/TXT.pm @@ -5,6 +5,12 @@ use warnings; use parent 'Zonemaster::LDNS::RR'; +sub txtdata() { + my ($rr) = @_; + + return join( "", map { substr($rr->rdf($_ - 1), 1) } 1..$rr->rd_count() ); +} + 1; =head1 NAME @@ -21,6 +27,12 @@ A subclass of L, so it has all the methods of that class a =item txtdata() -Returns the text data. +Returns the concatenation of all the strings composing the data of the resource record. + +For example, if a TXT resource record has the following presentation format: + + txt.test.example. 3600 IN TXT "I " "am " "split up in " "lit" "tle pieces" + +then C returns the string C<"I am split up in little pieces">. =back diff --git a/src/LDNS.xs b/src/LDNS.xs index becb907..e4b63a9 100644 --- a/src/LDNS.xs +++ b/src/LDNS.xs @@ -1233,7 +1233,14 @@ packet_string(obj) Zonemaster::LDNS::Packet obj; CODE: RETVAL = ldns_pkt2str(obj); - RETVAL[strlen(RETVAL)-1] = '\0'; + if(RETVAL == NULL || RETVAL[0] == '\0') + { + croak("Failed to convert packet to string"); + } + else + { + strip_newline(RETVAL); + } OUTPUT: RETVAL CLEANUP: @@ -1407,6 +1414,76 @@ packet_needs_edns(obj) OUTPUT: RETVAL +# +# Function: nsid +# -------------- +# Set the EDNS option NSID in the packet +# +void +packet_nsid(obj) + Zonemaster::LDNS::Packet obj; + CODE: + { +#ifdef NSID_SUPPORT + ldns_edns_option_list* edns_list; + ldns_edns_option* edns_opt; + + edns_list = ldns_pkt_edns_get_option_list(obj); + + if ( !edns_list ) + edns_list = ldns_edns_option_list_new(); + + edns_opt = ldns_edns_new_from_data(LDNS_EDNS_NSID, 0, NULL); + if ( edns_list == NULL || edns_opt == NULL ) + croak("Could not allocate EDNS option"); + if ( ! ldns_edns_option_list_push(edns_list, edns_opt) ) + croak("Could not attach EDNS option NSID"); + ldns_pkt_set_edns_option_list(obj, edns_list); +#else + croak("NSID not supported"); +#endif + } + +# +# Function: get_nsid +# ------------------ +# Get the EDNS option NSID if any from the packet +# +# returns: a bytes string (or undef if no NSID is found) +# +SV * +packet_get_nsid(obj) + Zonemaster::LDNS::Packet obj; + CODE: + { +#ifdef NSID_SUPPORT + ldns_edns_option_list* edns_list; + ldns_edns_option* edns_opt; + size_t i,count; + + edns_list = ldns_pkt_edns_get_option_list(obj); + if ( edns_list == NULL ) + XSRETURN_UNDEF; + + RETVAL = NULL; + count = ldns_edns_option_list_get_count(edns_list); + for ( i=0; inew('domain.example'); + $pkt->nsid; # set the NSID EDNS option + my $res = Zonemaster::LDNS->new($host)->query_with_pkt($pkt); + + my $nsid = $res->get_nsid(); + + is( $nsid, $expected_nsid, 'Correct NSID' ); +}; + +done_testing(); diff --git a/t/packet.t b/t/packet.t index 0d55feb..8be8565 100644 --- a/t/packet.t +++ b/t/packet.t @@ -28,4 +28,35 @@ is($p->answerfrom, undef, 'No answerfrom'); $p->answerfrom('127.0.0.1'); is($p->answerfrom, '127.0.0.1', 'Localhost'); +subtest "croak when stringifying packet with malformed CAA" => sub { + my $will_croak = sub { + # Constructing a synthetic packet that would have the following string + # representation in dig-like format: + # + # ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 13944 + # ;; flags: qr aa ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 + # ;; QUESTION SECTION: + # ;; bad-caa.example. IN CAA + # + # ;; ANSWER SECTION: + # bad-caa.example. 3600 IN CAA \# 4 C0000202 + # + # ;; AUTHORITY SECTION: + # + # ;; ADDITIONAL SECTION: + my $packet_bin = pack( + 'H*', + '367884000001000100000000' . # header + '076261642d636161076578616d706c650001010001' . # question + 'c00c0101000100000e100004c0000202' # bad answer + ); + + my $packet = Zonemaster::LDNS::Packet->new_from_wireformat( $packet_bin ); + + # This must croak + $packet->string; + }; + like( exception { $will_croak->() }, qr/^Failed to convert packet to string/ ); +}; + done_testing(); diff --git a/t/rr.t b/t/rr.t index 9b7aa66..ab7420f 100644 --- a/t/rr.t +++ b/t/rr.t @@ -77,18 +77,18 @@ subtest 'AAAA' => sub { }; subtest 'TXT' => sub { - SKIP: { - skip 'no network', 1 unless $ENV{TEST_WITH_NETWORK}; - - my $se = Zonemaster::LDNS->new( '192.36.144.107' ); - my $pt = $se->query( 'se', 'TXT' ); - plan skip_all => 'No response, cannot test' if not $pt; - - foreach my $rr ( $pt->answer ) { - isa_ok( $rr, 'Zonemaster::LDNS::RR::TXT' ); - like( $rr->txtdata, qr/^"SE zone update: / ); - } + my @data = ( + q{txt.test. 3600 IN TXT "Handling TXT RRs can be challenging"}, + q{txt.test. 3600 IN TXT "because " "the data can " "be spl" "it up like " "this!"} + ); + my @rrs = map { Zonemaster::LDNS::RR->new($_) } @data; + + foreach my $rr ( @rrs ) { + isa_ok( $rr, 'Zonemaster::LDNS::RR::TXT' ); } + + is( $rrs[0]->txtdata(), q{Handling TXT RRs can be challenging} ); + is( $rrs[1]->txtdata(), q{because the data can be split up like this!} ); }; subtest 'DNSKEY' => sub { @@ -220,10 +220,30 @@ subtest 'SRV' => sub { }; subtest 'SPF' => sub { - my $spf = Zonemaster::LDNS::RR->new( - 'frobbit.se. 1127 IN SPF "v=spf1 ip4:85.30.129.185/24 mx:mail.frobbit.se ip6:2a02:80:3ffe::0/64 ~all"' ); - isa_ok( $spf, 'Zonemaster::LDNS::RR::SPF' ); - is( $spf->spfdata, '"v=spf1 ip4:85.30.129.185/24 mx:mail.frobbit.se ip6:2a02:80:3ffe::0/64 ~all"' ); + my @data = ( + q{frobbit.se. 1127 IN SPF "v=spf1 ip4:85.30.129.185/24 mx:mail.frobbit.se ip6:2a02:80:3ffe::0/64 ~all"}, + q{spf.example. 3600 IN SPF "v=spf1 " "ip4:192.0.2.25/24 " "mx:mail.spf.example " "ip6:2001:db8::25/64 -all"} + ); + + my @rr = map { Zonemaster::LDNS::RR->new($_) } @data; + for my $spf (@rr) { + isa_ok( $spf, 'Zonemaster::LDNS::RR::SPF' ); + } + + is( $rr[0]->spfdata(), 'v=spf1 ip4:85.30.129.185/24 mx:mail.frobbit.se ip6:2a02:80:3ffe::0/64 ~all' ); + is( $rr[1]->spfdata(), 'v=spf1 ip4:192.0.2.25/24 mx:mail.spf.example ip6:2001:db8::25/64 -all' ); + +}; + +subtest 'croak when given malformed CAA records' => sub { + my $will_croak = sub { + # This will croak if LDNS.xs is compiled with -DUSE_ITHREADS + my $bad_caa = Zonemaster::LDNS::RR->new( + 'bad-caa.example. 3600 IN CAA \# 4 C0000202' ); + # This will always croak + $bad_caa->string(); + }; + like( exception { $will_croak->() }, qr/^Failed to convert RR to string/ ); }; done_testing;