Net-LDNS-0.75/000755 000770 000024 00000000000 12510741546 013321 5ustar00calledstaff000000 000000 Net-LDNS-0.75/Changes000644 000770 000024 00000000775 12510717703 014623 0ustar00calledstaff000000 000000 Revision history for Net::LDNS 0.75 2015-04-07 - Add method to get/set source IP address on resolvers. - Do SvGETMAGIC on SVs we get from outside. - Packets created from wireformat were not properly cloned. - Remove checks that did more harm than good (SvOK does not process get magic). 0.74 2015-03-23 - A number of memory leaks plugged. 0.73 2015-03-19 - Thread safety. 0.71 2015-02-18 - Ship the ldns code with the module rather than relying on an externally installed library. 0.70 2014-10-27 Net-LDNS-0.75/inc/000755 000770 000024 00000000000 12510741546 014072 5ustar00calledstaff000000 000000 Net-LDNS-0.75/include/000755 000770 000024 00000000000 12510741546 014744 5ustar00calledstaff000000 000000 Net-LDNS-0.75/lib/000755 000770 000024 00000000000 12510741546 014067 5ustar00calledstaff000000 000000 Net-LDNS-0.75/LICENSE000644 000770 000024 00000002376 12241170502 014323 0ustar00calledstaff000000 000000 Copyright (c) 2013 .SE (The Internet Infrastructure Foundation). All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Net-LDNS-0.75/Makefile.PL000644 000770 000024 00000005556 12502502027 015274 0ustar00calledstaff000000 000000 use inc::Module::Install; use Devel::CheckLib; use Getopt::Long; use File::Spec::Functions; BEGIN { if ( $Module::Install::AUTHOR ) { use Module::Install::XSUtil; } } my $headdir; my $libdir; my $prefix; my $randomize; GetOptions( 'headers=s' => \$headdir, 'libs=s' => \$libdir, 'prefix=s' => \$prefix, 'randomize!' => \$randomize, ); if ( $prefix ) { $headdir = catdir( $prefix, 'include' ); $libdir = catdir( $prefix, 'lib' ); } cc_include_paths( $headdir ) if $headdir; cc_libs( '-L' . $libdir ) if $libdir; cc_include_paths( 'include' ); name 'Net-LDNS'; version_from 'lib/Net/LDNS.pm'; license 'bsd'; author 'Calle Dybedahl '; abstract 'Perl wrapper for the ldns DNS library.'; perl_version '5.010001'; configure_requires 'Devel::CheckLib'; requires 'MIME::Base64'; test_requires 'JSON::PP'; test_requires 'Test::Fatal'; use_ppport 3.19; cc_libs 'crypto'; cc_src_paths 'src'; my %assert_args = ( lib => 'crypto', header => 'openssl/crypto.h', function => 'if(SSLeay()) return 0; else return 1;' ); $assert_args{LIBS} = '-L' . $libdir if $libdir; $assert_args{INC} = '-I' . $headdir if $headdir; cc_assert_lib %assert_args; if (not check_ecdsa(%assert_args)) { print "Your OpenSSL does not seem to support ECDSA.\n"; exit; } else { print "ECDSA support detected.\n"; } if (not check_gost(%assert_args)) { print "Your OpenSSL does not seem to support GOST.\n"; } else { print "GOST support detected.\n"; cc_define '-DUSE_GOST'; } if ( check_lib( lib => 'idn', header => 'idna.h', function => 'if(strcmp(IDNA_ACE_PREFIX,"xn--")==0) return 0; else return 1;' ) ) { cc_libs 'idn'; cc_define '-DWE_CAN_HAZ_IDN'; print "IDNA support detected.\n"; } if ( $randomize ) { cc_define '-DRANDOMIZE'; print( ( "=" x 65 ) . "\n" ); print "Compiling with randomzied capitalization.\n"; print( ( "=" x 65 ) . "\n" ); } WriteAll; sub check_ecdsa { my %args = @_; $args{header} = [ 'openssl/crypto.h', 'openssl/ecdsa.h' ]; $args{function} = q[if(ECDSA_SIG_new()) return 0; else return 1;]; return check_lib(%args); } sub check_gost { my %args = @_; $args{header} = [ 'openssl/crypto.h', 'openssl/ecdsa.h', 'openssl/engine.h' ]; $args{function} = <<'CODE'; const EVP_PKEY_ASN1_METHOD* meth; ENGINE* e; meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1); if(meth) { return 0; } e = ENGINE_by_id("gost"); if(!e) { ENGINE_load_builtin_engines(); ENGINE_load_dynamic(); e = ENGINE_by_id("gost"); } if(!e) { return 1; } if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { return 1; } meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1); if(!meth) { return 1; } return 0; CODE return check_lib(%args); }Net-LDNS-0.75/MANIFEST000644 000770 000024 00000007255 12510741376 014464 0ustar00calledstaff000000 000000 Changes inc/Module/Install.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm inc/Module/Install/XSUtil.pm include/LDNS.h include/ldns/buffer.h include/ldns/common.h include/ldns/config.h include/ldns/dane.h include/ldns/dname.h include/ldns/dnssec.h include/ldns/dnssec_sign.h include/ldns/dnssec_verify.h include/ldns/dnssec_zone.h include/ldns/duration.h include/ldns/error.h include/ldns/higher.h include/ldns/host2str.h include/ldns/host2wire.h include/ldns/keys.h include/ldns/ldns.h include/ldns/net.h include/ldns/packet.h include/ldns/parse.h include/ldns/radix.h include/ldns/rbtree.h include/ldns/rdata.h include/ldns/resolver.h include/ldns/rr.h include/ldns/rr_functions.h include/ldns/sha1.h include/ldns/sha2.h include/ldns/str2host.h include/ldns/tsig.h include/ldns/update.h include/ldns/util.h include/ldns/wire2host.h include/ldns/zone.h lib/Net/LDNS.pm lib/Net/LDNS/Packet.pm lib/Net/LDNS/RR.pm lib/Net/LDNS/RR/A.pm lib/Net/LDNS/RR/A6.pm lib/Net/LDNS/RR/AAAA.pm lib/Net/LDNS/RR/AFSDB.pm lib/Net/LDNS/RR/APL.pm lib/Net/LDNS/RR/ATMA.pm lib/Net/LDNS/RR/CAA.pm lib/Net/LDNS/RR/CDS.pm lib/Net/LDNS/RR/CERT.pm lib/Net/LDNS/RR/CNAME.pm lib/Net/LDNS/RR/DHCID.pm lib/Net/LDNS/RR/DLV.pm lib/Net/LDNS/RR/DNAME.pm lib/Net/LDNS/RR/DNSKEY.pm lib/Net/LDNS/RR/DS.pm lib/Net/LDNS/RR/EID.pm lib/Net/LDNS/RR/EUI48.pm lib/Net/LDNS/RR/EUI64.pm lib/Net/LDNS/RR/GID.pm lib/Net/LDNS/RR/GPOS.pm lib/Net/LDNS/RR/HINFO.pm lib/Net/LDNS/RR/HIP.pm lib/Net/LDNS/RR/IPSECKEY.pm lib/Net/LDNS/RR/ISDN.pm lib/Net/LDNS/RR/KEY.pm lib/Net/LDNS/RR/KX.pm lib/Net/LDNS/RR/L32.pm lib/Net/LDNS/RR/L64.pm lib/Net/LDNS/RR/LOC.pm lib/Net/LDNS/RR/LP.pm lib/Net/LDNS/RR/MAILA.pm lib/Net/LDNS/RR/MAILB.pm lib/Net/LDNS/RR/MB.pm lib/Net/LDNS/RR/MD.pm lib/Net/LDNS/RR/MF.pm lib/Net/LDNS/RR/MG.pm lib/Net/LDNS/RR/MINFO.pm lib/Net/LDNS/RR/MR.pm lib/Net/LDNS/RR/MX.pm lib/Net/LDNS/RR/NAPTR.pm lib/Net/LDNS/RR/NID.pm lib/Net/LDNS/RR/NIMLOC.pm lib/Net/LDNS/RR/NINFO.pm lib/Net/LDNS/RR/NS.pm lib/Net/LDNS/RR/NSAP.pm lib/Net/LDNS/RR/NSEC.pm lib/Net/LDNS/RR/NSEC3.pm lib/Net/LDNS/RR/NSEC3PARAM.pm lib/Net/LDNS/RR/NULL.pm lib/Net/LDNS/RR/NXT.pm lib/Net/LDNS/RR/PTR.pm lib/Net/LDNS/RR/PX.pm lib/Net/LDNS/RR/RKEY.pm lib/Net/LDNS/RR/RP.pm lib/Net/LDNS/RR/RRSIG.pm lib/Net/LDNS/RR/RT.pm lib/Net/LDNS/RR/SIG.pm lib/Net/LDNS/RR/SINK.pm lib/Net/LDNS/RR/SOA.pm lib/Net/LDNS/RR/SPF.pm lib/Net/LDNS/RR/SRV.pm lib/Net/LDNS/RR/SSHFP.pm lib/Net/LDNS/RR/TA.pm lib/Net/LDNS/RR/TALINK.pm lib/Net/LDNS/RR/TKEY.pm lib/Net/LDNS/RR/TLSA.pm lib/Net/LDNS/RR/TXT.pm lib/Net/LDNS/RR/TYPE.pm lib/Net/LDNS/RR/UID.pm lib/Net/LDNS/RR/UINFO.pm lib/Net/LDNS/RR/UNSPEC.pm lib/Net/LDNS/RR/URI.pm lib/Net/LDNS/RR/WKS.pm lib/Net/LDNS/RR/X25.pm lib/Net/LDNS/RRList.pm LICENSE Makefile.PL MANIFEST This list of files META.yml ppport.h README.md src/assist.c src/LDNS.xs src/ldns/compat/b64_ntop.c src/ldns/compat/b64_pton.c src/ldns/buffer.c src/ldns/compat/strlcpy.c src/ldns/dane.c src/ldns/dname.c src/ldns/dnssec.c src/ldns/dnssec_sign.c src/ldns/dnssec_verify.c src/ldns/dnssec_zone.c src/ldns/duration.c src/ldns/error.c src/ldns/higher.c src/ldns/host2str.c src/ldns/host2wire.c src/ldns/keys.c src/ldns/net.c src/ldns/packet.c src/ldns/parse.c src/ldns/radix.c src/ldns/rbtree.c src/ldns/rdata.c src/ldns/resolver.c src/ldns/rr.c src/ldns/rr_functions.c src/ldns/sha1.c src/ldns/sha2.c src/ldns/str2host.c src/ldns/tsig.c src/ldns/update.c src/ldns/util.c src/ldns/wire2host.c src/ldns/zone.c src/typemap t/axfr.t t/dnssec.t t/example.org t/idn.t t/load_zonefile.t t/netldns.t t/packet.t t/regression.t t/resolver.t t/rr.t t/rrlist.t t/serialize.t t/threads.t t/utils.t Net-LDNS-0.75/META.yml000644 000770 000024 00000001337 12510720200 014556 0ustar00calledstaff000000 000000 --- abstract: 'Perl wrapper for the ldns DNS library.' author: - 'Calle Dybedahl ' build_requires: Devel::CheckLib: '0.4' Devel::PPPort: 3.19 ExtUtils::MakeMaker: 6.59 JSON::PP: 0 Test::Fatal: 0 configure_requires: Devel::CheckLib: '0.4' Devel::PPPort: 3.19 ExtUtils::MakeMaker: 6.59 ExtUtils::ParseXS: 3.18 distribution_type: module dynamic_config: 1 generated_by: 'Module::Install version 1.14' license: bsd meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Net-LDNS no_index: directory: - inc - t requires: MIME::Base64: 0 XSLoader: 0.02 perl: 5.10.1 resources: license: http://opensource.org/licenses/bsd-license.php version: '0.75' Net-LDNS-0.75/ppport.h000644 000770 000024 00000575363 12510720176 015035 0ustar00calledstaff000000 000000 #if 0 <<'SKIP'; #endif /* ---------------------------------------------------------------------- ppport.h -- Perl/Pollution/Portability Version 3.28 Automatically created by Devel::PPPort running under perl 5.020002. Do NOT edit this file directly! -- Edit PPPort_pm.PL and the includes in parts/inc/ instead. Use 'perldoc ppport.h' to view the documentation below. ---------------------------------------------------------------------- SKIP =pod =head1 NAME ppport.h - Perl/Pollution/Portability version 3.28 =head1 SYNOPSIS perl ppport.h [options] [source files] Searches current directory for files if no [source files] are given --help show short help --version show version --patch=file write one patch file with changes --copy=suffix write changed copies with suffix --diff=program use diff program and options --compat-version=version provide compatibility with Perl version --cplusplus accept C++ comments --quiet don't output anything except fatal errors --nodiag don't show diagnostics --nohints don't show hints --nochanges don't suggest changes --nofilter don't filter input files --strip strip all script and doc functionality from ppport.h --list-provided list provided API --list-unsupported list unsupported API --api-info=name show Perl API portability information =head1 COMPATIBILITY This version of F is designed to support operation with Perl installations back to 5.003, and has been tested up to 5.20. =head1 OPTIONS =head2 --help Display a brief usage summary. =head2 --version Display the version of F. =head2 --patch=I If this option is given, a single patch file will be created if any changes are suggested. This requires a working diff program to be installed on your system. =head2 --copy=I If this option is given, a copy of each file will be saved with the given suffix that contains the suggested changes. This does not require any external programs. Note that this does not automagically add a dot between the original filename and the suffix. If you want the dot, you have to include it in the option argument. If neither C<--patch> or C<--copy> are given, the default is to simply print the diffs for each file. This requires either C or a C program to be installed. =head2 --diff=I Manually set the diff program and options to use. The default is to use C, when installed, and output unified context diffs. =head2 --compat-version=I Tell F to check for compatibility with the given Perl version. The default is to check for compatibility with Perl version 5.003. You can use this option to reduce the output of F if you intend to be backward compatible only down to a certain Perl version. =head2 --cplusplus Usually, F will detect C++ style comments and replace them with C style comments for portability reasons. Using this option instructs F to leave C++ comments untouched. =head2 --quiet Be quiet. Don't print anything except fatal errors. =head2 --nodiag Don't output any diagnostic messages. Only portability alerts will be printed. =head2 --nohints Don't output any hints. Hints often contain useful portability notes. Warnings will still be displayed. =head2 --nochanges Don't suggest any changes. Only give diagnostic output and hints unless these are also deactivated. =head2 --nofilter Don't filter the list of input files. By default, files not looking like source code (i.e. not *.xs, *.c, *.cc, *.cpp or *.h) are skipped. =head2 --strip Strip all script and documentation functionality from F. This reduces the size of F dramatically and may be useful if you want to include F in smaller modules without increasing their distribution size too much. The stripped F will have a C<--unstrip> option that allows you to undo the stripping, but only if an appropriate C module is installed. =head2 --list-provided Lists the API elements for which compatibility is provided by F. Also lists if it must be explicitly requested, if it has dependencies, and if there are hints or warnings for it. =head2 --list-unsupported Lists the API elements that are known not to be supported by F and below which version of Perl they probably won't be available or work. =head2 --api-info=I Show portability information for API elements matching I. If I is surrounded by slashes, it is interpreted as a regular expression. =head1 DESCRIPTION In order for a Perl extension (XS) module to be as portable as possible across differing versions of Perl itself, certain steps need to be taken. =over 4 =item * Including this header is the first major one. This alone will give you access to a large part of the Perl API that hasn't been available in earlier Perl releases. Use perl ppport.h --list-provided to see which API elements are provided by ppport.h. =item * You should avoid using deprecated parts of the API. For example, using global Perl variables without the C prefix is deprecated. Also, some API functions used to have a C prefix. Using this form is also deprecated. You can safely use the supported API, as F will provide wrappers for older Perl versions. =item * If you use one of a few functions or variables that were not present in earlier versions of Perl, and that can't be provided using a macro, you have to explicitly request support for these functions by adding one or more C<#define>s in your source code before the inclusion of F. These functions or variables will be marked C in the list shown by C<--list-provided>. Depending on whether you module has a single or multiple files that use such functions or variables, you want either C or global variants. For a C function or variable (used only in a single source file), use: #define NEED_function #define NEED_variable For a global function or variable (used in multiple source files), use: #define NEED_function_GLOBAL #define NEED_variable_GLOBAL Note that you mustn't have more than one global request for the same function or variable in your project. Function / Variable Static Request Global Request ----------------------------------------------------------------------------------------- PL_parser NEED_PL_parser NEED_PL_parser_GLOBAL PL_signals NEED_PL_signals NEED_PL_signals_GLOBAL caller_cx() NEED_caller_cx NEED_caller_cx_GLOBAL eval_pv() NEED_eval_pv NEED_eval_pv_GLOBAL grok_bin() NEED_grok_bin NEED_grok_bin_GLOBAL grok_hex() NEED_grok_hex NEED_grok_hex_GLOBAL grok_number() NEED_grok_number NEED_grok_number_GLOBAL grok_numeric_radix() NEED_grok_numeric_radix NEED_grok_numeric_radix_GLOBAL grok_oct() NEED_grok_oct NEED_grok_oct_GLOBAL load_module() NEED_load_module NEED_load_module_GLOBAL mg_findext() NEED_mg_findext NEED_mg_findext_GLOBAL my_snprintf() NEED_my_snprintf NEED_my_snprintf_GLOBAL my_sprintf() NEED_my_sprintf NEED_my_sprintf_GLOBAL my_strlcat() NEED_my_strlcat NEED_my_strlcat_GLOBAL my_strlcpy() NEED_my_strlcpy NEED_my_strlcpy_GLOBAL newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL newRV_noinc() NEED_newRV_noinc NEED_newRV_noinc_GLOBAL newSV_type() NEED_newSV_type NEED_newSV_type_GLOBAL newSVpvn_flags() NEED_newSVpvn_flags NEED_newSVpvn_flags_GLOBAL newSVpvn_share() NEED_newSVpvn_share NEED_newSVpvn_share_GLOBAL pv_display() NEED_pv_display NEED_pv_display_GLOBAL pv_escape() NEED_pv_escape NEED_pv_escape_GLOBAL pv_pretty() NEED_pv_pretty NEED_pv_pretty_GLOBAL sv_2pv_flags() NEED_sv_2pv_flags NEED_sv_2pv_flags_GLOBAL sv_2pvbyte() NEED_sv_2pvbyte NEED_sv_2pvbyte_GLOBAL sv_catpvf_mg() NEED_sv_catpvf_mg NEED_sv_catpvf_mg_GLOBAL sv_catpvf_mg_nocontext() NEED_sv_catpvf_mg_nocontext NEED_sv_catpvf_mg_nocontext_GLOBAL sv_pvn_force_flags() NEED_sv_pvn_force_flags NEED_sv_pvn_force_flags_GLOBAL sv_setpvf_mg() NEED_sv_setpvf_mg NEED_sv_setpvf_mg_GLOBAL sv_setpvf_mg_nocontext() NEED_sv_setpvf_mg_nocontext NEED_sv_setpvf_mg_nocontext_GLOBAL sv_unmagicext() NEED_sv_unmagicext NEED_sv_unmagicext_GLOBAL vload_module() NEED_vload_module NEED_vload_module_GLOBAL vnewSVpvf() NEED_vnewSVpvf NEED_vnewSVpvf_GLOBAL warner() NEED_warner NEED_warner_GLOBAL To avoid namespace conflicts, you can change the namespace of the explicitly exported functions / variables using the C macro. Just C<#define> the macro before including C: #define DPPP_NAMESPACE MyOwnNamespace_ #include "ppport.h" The default namespace is C. =back The good thing is that most of the above can be checked by running F on your source code. See the next section for details. =head1 EXAMPLES To verify whether F is needed for your module, whether you should make any changes to your code, and whether any special defines should be used, F can be run as a Perl script to check your source code. Simply say: perl ppport.h The result will usually be a list of patches suggesting changes that should at least be acceptable, if not necessarily the most efficient solution, or a fix for all possible problems. If you know that your XS module uses features only available in newer Perl releases, if you're aware that it uses C++ comments, and if you want all suggestions as a single patch file, you could use something like this: perl ppport.h --compat-version=5.6.0 --cplusplus --patch=test.diff If you only want your code to be scanned without any suggestions for changes, use: perl ppport.h --nochanges You can specify a different C program or options, using the C<--diff> option: perl ppport.h --diff='diff -C 10' This would output context diffs with 10 lines of context. If you want to create patched copies of your files instead, use: perl ppport.h --copy=.new To display portability information for the C function, use: perl ppport.h --api-info=newSVpvn Since the argument to C<--api-info> can be a regular expression, you can use perl ppport.h --api-info=/_nomg$/ to display portability information for all C<_nomg> functions or perl ppport.h --api-info=/./ to display information for all known API elements. =head1 BUGS If this version of F is causing failure during the compilation of this module, please check if newer versions of either this module or C are available on CPAN before sending a bug report. If F was generated using the latest version of C and is causing failure of this module, please file a bug report here: L Please include the following information: =over 4 =item 1. The complete output from running "perl -V" =item 2. This file. =item 3. The name and version of the module you were trying to build. =item 4. A full log of the build that failed. =item 5. Any other information that you think could be relevant. =back For the latest version of this code, please get the C module from CPAN. =head1 COPYRIGHT Version 3.x, Copyright (c) 2004-2013, Marcus Holland-Moritz. Version 2.x, Copyright (C) 2001, Paul Marquess. Version 1.x, Copyright (C) 1999, Kenneth Albanowski. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO See L. =cut use strict; # Disable broken TRIE-optimization BEGIN { eval '${^RE_TRIE_MAXBUF} = -1' if $] >= 5.009004 && $] <= 5.009005 } my $VERSION = 3.28; my %opt = ( quiet => 0, diag => 1, hints => 1, changes => 1, cplusplus => 0, filter => 1, strip => 0, version => 0, ); my($ppport) = $0 =~ /([\w.]+)$/; my $LF = '(?:\r\n|[\r\n])'; # line feed my $HS = "[ \t]"; # horizontal whitespace # Never use C comments in this file! my $ccs = '/'.'*'; my $cce = '*'.'/'; my $rccs = quotemeta $ccs; my $rcce = quotemeta $cce; eval { require Getopt::Long; Getopt::Long::GetOptions(\%opt, qw( help quiet diag! filter! hints! changes! cplusplus strip version patch=s copy=s diff=s compat-version=s list-provided list-unsupported api-info=s )) or usage(); }; if ($@ and grep /^-/, @ARGV) { usage() if "@ARGV" =~ /^--?h(?:elp)?$/; die "Getopt::Long not found. Please don't use any options.\n"; } if ($opt{version}) { print "This is $0 $VERSION.\n"; exit 0; } usage() if $opt{help}; strip() if $opt{strip}; if (exists $opt{'compat-version'}) { my($r,$v,$s) = eval { parse_version($opt{'compat-version'}) }; if ($@) { die "Invalid version number format: '$opt{'compat-version'}'\n"; } die "Only Perl 5 is supported\n" if $r != 5; die "Invalid version number: $opt{'compat-version'}\n" if $v >= 1000 || $s >= 1000; $opt{'compat-version'} = sprintf "%d.%03d%03d", $r, $v, $s; } else { $opt{'compat-version'} = 5; } my %API = map { /^(\w+)\|([^|]*)\|([^|]*)\|(\w*)$/ ? ( $1 => { ($2 ? ( base => $2 ) : ()), ($3 ? ( todo => $3 ) : ()), (index($4, 'v') >= 0 ? ( varargs => 1 ) : ()), (index($4, 'p') >= 0 ? ( provided => 1 ) : ()), (index($4, 'n') >= 0 ? ( nothxarg => 1 ) : ()), } ) : die "invalid spec: $_" } qw( ASCII_TO_NEED||5.007001|n AvFILLp|5.004050||p AvFILL||| BhkDISABLE||5.021008| BhkENABLE||5.021008| BhkENTRY_set||5.021008| BhkENTRY||| BhkFLAGS||| CALL_BLOCK_HOOKS||| CLASS|||n CPERLscope|5.005000||p CX_CURPAD_SAVE||| CX_CURPAD_SV||| CopFILEAV|5.006000||p CopFILEGV_set|5.006000||p CopFILEGV|5.006000||p CopFILESV|5.006000||p CopFILE_set|5.006000||p CopFILE|5.006000||p CopSTASHPV_set|5.006000||p CopSTASHPV|5.006000||p CopSTASH_eq|5.006000||p CopSTASH_set|5.006000||p CopSTASH|5.006000||p CopyD|5.009002|5.004050|p Copy||| CvPADLIST||5.008001| CvSTASH||| CvWEAKOUTSIDE||| DEFSV_set|5.010001||p DEFSV|5.004050||p END_EXTERN_C|5.005000||p ENTER||| ERRSV|5.004050||p EXTEND||| EXTERN_C|5.005000||p F0convert|||n FREETMPS||| GIMME_V||5.004000|n GIMME|||n GROK_NUMERIC_RADIX|5.007002||p G_ARRAY||| G_DISCARD||| G_EVAL||| G_METHOD|5.006001||p G_NOARGS||| G_SCALAR||| G_VOID||5.004000| GetVars||| GvAV||| GvCV||| GvHV||| GvSVn|5.009003||p GvSV||| Gv_AMupdate||5.011000| HEf_SVKEY|5.003070||p HeHASH||5.003070| HeKEY||5.003070| HeKLEN||5.003070| HePV||5.004000| HeSVKEY_force||5.003070| HeSVKEY_set||5.004000| HeSVKEY||5.003070| HeUTF8|5.010001|5.008000|p HeVAL||5.003070| HvENAMELEN||5.015004| HvENAMEUTF8||5.015004| HvENAME||5.013007| HvNAMELEN_get|5.009003||p HvNAMELEN||5.015004| HvNAMEUTF8||5.015004| HvNAME_get|5.009003||p HvNAME||| INT2PTR|5.006000||p IN_LOCALE_COMPILETIME|5.007002||p IN_LOCALE_RUNTIME|5.007002||p IN_LOCALE|5.007002||p IN_PERL_COMPILETIME|5.008001||p IS_NUMBER_GREATER_THAN_UV_MAX|5.007002||p IS_NUMBER_INFINITY|5.007002||p IS_NUMBER_IN_UV|5.007002||p IS_NUMBER_NAN|5.007003||p IS_NUMBER_NEG|5.007002||p IS_NUMBER_NOT_INT|5.007002||p IVSIZE|5.006000||p IVTYPE|5.006000||p IVdf|5.006000||p LEAVE||| LINKLIST||5.013006| LVRET||| MARK||| MULTICALL||5.021008| MUTABLE_PTR|5.010001||p MUTABLE_SV|5.010001||p MY_CXT_CLONE|5.009002||p MY_CXT_INIT|5.007003||p MY_CXT|5.007003||p MoveD|5.009002|5.004050|p Move||| NATIVE_TO_NEED||5.007001|n NOOP|5.005000||p NUM2PTR|5.006000||p NVTYPE|5.006000||p NVef|5.006001||p NVff|5.006001||p NVgf|5.006001||p Newxc|5.009003||p Newxz|5.009003||p Newx|5.009003||p Nullav||| Nullch||| Nullcv||| Nullhv||| Nullsv||| OP_CLASS||5.013007| OP_DESC||5.007003| OP_NAME||5.007003| OP_TYPE_IS_OR_WAS||5.019010| OP_TYPE_IS||5.019007| ORIGMARK||| OpHAS_SIBLING||5.021007| OpSIBLING_set||5.021007| OpSIBLING||5.021007| PAD_BASE_SV||| PAD_CLONE_VARS||| PAD_COMPNAME_FLAGS||| PAD_COMPNAME_GEN_set||| PAD_COMPNAME_GEN||| PAD_COMPNAME_OURSTASH||| PAD_COMPNAME_PV||| PAD_COMPNAME_TYPE||| PAD_RESTORE_LOCAL||| PAD_SAVE_LOCAL||| PAD_SAVE_SETNULLPAD||| PAD_SETSV||| PAD_SET_CUR_NOSAVE||| PAD_SET_CUR||| PAD_SVl||| PAD_SV||| PERLIO_FUNCS_CAST|5.009003||p PERLIO_FUNCS_DECL|5.009003||p PERL_ABS|5.008001||p PERL_BCDVERSION|5.021008||p PERL_GCC_BRACE_GROUPS_FORBIDDEN|5.008001||p PERL_HASH|5.003070||p PERL_INT_MAX|5.003070||p PERL_INT_MIN|5.003070||p PERL_LONG_MAX|5.003070||p PERL_LONG_MIN|5.003070||p PERL_MAGIC_arylen|5.007002||p PERL_MAGIC_backref|5.007002||p PERL_MAGIC_bm|5.007002||p PERL_MAGIC_collxfrm|5.007002||p PERL_MAGIC_dbfile|5.007002||p PERL_MAGIC_dbline|5.007002||p PERL_MAGIC_defelem|5.007002||p PERL_MAGIC_envelem|5.007002||p PERL_MAGIC_env|5.007002||p PERL_MAGIC_ext|5.007002||p PERL_MAGIC_fm|5.007002||p PERL_MAGIC_glob|5.021008||p PERL_MAGIC_isaelem|5.007002||p PERL_MAGIC_isa|5.007002||p PERL_MAGIC_mutex|5.021008||p PERL_MAGIC_nkeys|5.007002||p PERL_MAGIC_overload_elem|5.021008||p PERL_MAGIC_overload_table|5.007002||p PERL_MAGIC_overload|5.021008||p PERL_MAGIC_pos|5.007002||p PERL_MAGIC_qr|5.007002||p PERL_MAGIC_regdata|5.007002||p PERL_MAGIC_regdatum|5.007002||p PERL_MAGIC_regex_global|5.007002||p PERL_MAGIC_shared_scalar|5.007003||p PERL_MAGIC_shared|5.007003||p PERL_MAGIC_sigelem|5.007002||p PERL_MAGIC_sig|5.007002||p PERL_MAGIC_substr|5.007002||p PERL_MAGIC_sv|5.007002||p PERL_MAGIC_taint|5.007002||p PERL_MAGIC_tiedelem|5.007002||p PERL_MAGIC_tiedscalar|5.007002||p PERL_MAGIC_tied|5.007002||p PERL_MAGIC_utf8|5.008001||p PERL_MAGIC_uvar_elem|5.007003||p PERL_MAGIC_uvar|5.007002||p PERL_MAGIC_vec|5.007002||p PERL_MAGIC_vstring|5.008001||p PERL_PV_ESCAPE_ALL|5.009004||p PERL_PV_ESCAPE_FIRSTCHAR|5.009004||p PERL_PV_ESCAPE_NOBACKSLASH|5.009004||p PERL_PV_ESCAPE_NOCLEAR|5.009004||p PERL_PV_ESCAPE_QUOTE|5.009004||p PERL_PV_ESCAPE_RE|5.009005||p PERL_PV_ESCAPE_UNI_DETECT|5.009004||p PERL_PV_ESCAPE_UNI|5.009004||p PERL_PV_PRETTY_DUMP|5.009004||p PERL_PV_PRETTY_ELLIPSES|5.010000||p PERL_PV_PRETTY_LTGT|5.009004||p PERL_PV_PRETTY_NOCLEAR|5.010000||p PERL_PV_PRETTY_QUOTE|5.009004||p PERL_PV_PRETTY_REGPROP|5.009004||p PERL_QUAD_MAX|5.003070||p PERL_QUAD_MIN|5.003070||p PERL_REVISION|5.006000||p PERL_SCAN_ALLOW_UNDERSCORES|5.007003||p PERL_SCAN_DISALLOW_PREFIX|5.007003||p PERL_SCAN_GREATER_THAN_UV_MAX|5.007003||p PERL_SCAN_SILENT_ILLDIGIT|5.008001||p PERL_SHORT_MAX|5.003070||p PERL_SHORT_MIN|5.003070||p PERL_SIGNALS_UNSAFE_FLAG|5.008001||p PERL_SUBVERSION|5.006000||p PERL_SYS_INIT3||5.006000| PERL_SYS_INIT||| PERL_SYS_TERM||5.021008| PERL_UCHAR_MAX|5.003070||p PERL_UCHAR_MIN|5.003070||p PERL_UINT_MAX|5.003070||p PERL_UINT_MIN|5.003070||p PERL_ULONG_MAX|5.003070||p PERL_ULONG_MIN|5.003070||p PERL_UNUSED_ARG|5.009003||p PERL_UNUSED_CONTEXT|5.009004||p PERL_UNUSED_DECL|5.007002||p PERL_UNUSED_VAR|5.007002||p PERL_UQUAD_MAX|5.003070||p PERL_UQUAD_MIN|5.003070||p PERL_USE_GCC_BRACE_GROUPS|5.009004||p PERL_USHORT_MAX|5.003070||p PERL_USHORT_MIN|5.003070||p PERL_VERSION|5.006000||p PL_DBsignal|5.005000||p PL_DBsingle|||pn PL_DBsub|||pn PL_DBtrace|||pn PL_Sv|5.005000||p PL_bufend|5.021008||p PL_bufptr|5.021008||p PL_check||5.006000| PL_compiling|5.004050||p PL_comppad_name||5.017004| PL_comppad||5.008001| PL_copline|5.021008||p PL_curcop|5.004050||p PL_curpad||5.005000| PL_curstash|5.004050||p PL_debstash|5.004050||p PL_defgv|5.004050||p PL_diehook|5.004050||p PL_dirty|5.004050||p PL_dowarn|||pn PL_errgv|5.004050||p PL_error_count|5.021008||p PL_expect|5.021008||p PL_hexdigit|5.005000||p PL_hints|5.005000||p PL_in_my_stash|5.021008||p PL_in_my|5.021008||p PL_keyword_plugin||5.011002| PL_last_in_gv|||n PL_laststatval|5.005000||p PL_lex_state|5.021008||p PL_lex_stuff|5.021008||p PL_linestr|5.021008||p PL_modglobal||5.005000|n PL_na|5.004050||pn PL_no_modify|5.006000||p PL_ofsgv|||n PL_opfreehook||5.011000|n PL_parser|5.009005||p PL_peepp||5.007003|n PL_perl_destruct_level|5.004050||p PL_perldb|5.004050||p PL_ppaddr|5.006000||p PL_rpeepp||5.013005|n PL_rsfp_filters|5.021008||p PL_rsfp|5.021008||p PL_rs|||n PL_signals|5.008001||p PL_stack_base|5.004050||p PL_stack_sp|5.004050||p PL_statcache|5.005000||p PL_stdingv|5.004050||p PL_sv_arenaroot|5.004050||p PL_sv_no|5.004050||pn PL_sv_undef|5.004050||pn PL_sv_yes|5.004050||pn PL_tainted|5.004050||p PL_tainting|5.004050||p PL_tokenbuf|5.021008||p POP_MULTICALL||5.021008| POPi|||n POPl|||n POPn|||n POPpbytex||5.007001|n POPpx||5.005030|n POPp|||n POPs|||n PTR2IV|5.006000||p PTR2NV|5.006000||p PTR2UV|5.006000||p PTR2nat|5.009003||p PTR2ul|5.007001||p PTRV|5.006000||p PUSHMARK||| PUSH_MULTICALL||5.021008| PUSHi||| PUSHmortal|5.009002||p PUSHn||| PUSHp||| PUSHs||| PUSHu|5.004000||p PUTBACK||| PadARRAY||5.021008| PadMAX||5.021008| PadlistARRAY||5.021008| PadlistMAX||5.021008| PadlistNAMESARRAY||5.021008| PadlistNAMESMAX||5.021008| PadlistNAMES||5.021008| PadlistREFCNT||5.017004| PadnameIsOUR||| PadnameIsSTATE||| PadnameLEN||5.021008| PadnameOURSTASH||| PadnameOUTER||| PadnamePV||5.021008| PadnameREFCNT_dec||5.021008| PadnameREFCNT||5.021008| PadnameSV||5.021008| PadnameTYPE||| PadnameUTF8||5.021007| PadnamelistARRAY||5.021008| PadnamelistMAX||5.021008| PadnamelistREFCNT_dec||5.021008| PadnamelistREFCNT||5.021008| PerlIO_clearerr||5.007003| PerlIO_close||5.007003| PerlIO_context_layers||5.009004| PerlIO_eof||5.007003| PerlIO_error||5.007003| PerlIO_fileno||5.007003| PerlIO_fill||5.007003| PerlIO_flush||5.007003| PerlIO_get_base||5.007003| PerlIO_get_bufsiz||5.007003| PerlIO_get_cnt||5.007003| PerlIO_get_ptr||5.007003| PerlIO_read||5.007003| PerlIO_restore_errno||| PerlIO_save_errno||| PerlIO_seek||5.007003| PerlIO_set_cnt||5.007003| PerlIO_set_ptrcnt||5.007003| PerlIO_setlinebuf||5.007003| PerlIO_stderr||5.007003| PerlIO_stdin||5.007003| PerlIO_stdout||5.007003| PerlIO_tell||5.007003| PerlIO_unread||5.007003| PerlIO_write||5.007003| Perl_signbit||5.009005|n PoisonFree|5.009004||p PoisonNew|5.009004||p PoisonWith|5.009004||p Poison|5.008000||p READ_XDIGIT||5.017006| RETVAL|||n Renewc||| Renew||| SAVECLEARSV||| SAVECOMPPAD||| SAVEPADSV||| SAVETMPS||| SAVE_DEFSV|5.004050||p SPAGAIN||| SP||| START_EXTERN_C|5.005000||p START_MY_CXT|5.007003||p STMT_END|||p STMT_START|||p STR_WITH_LEN|5.009003||p ST||| SV_CONST_RETURN|5.009003||p SV_COW_DROP_PV|5.008001||p SV_COW_SHARED_HASH_KEYS|5.009005||p SV_GMAGIC|5.007002||p SV_HAS_TRAILING_NUL|5.009004||p SV_IMMEDIATE_UNREF|5.007001||p SV_MUTABLE_RETURN|5.009003||p SV_NOSTEAL|5.009002||p SV_SMAGIC|5.009003||p SV_UTF8_NO_ENCODING|5.008001||p SVfARG|5.009005||p SVf_UTF8|5.006000||p SVf|5.006000||p SVt_INVLIST||5.019002| SVt_IV||| SVt_NULL||| SVt_NV||| SVt_PVAV||| SVt_PVCV||| SVt_PVFM||| SVt_PVGV||| SVt_PVHV||| SVt_PVIO||| SVt_PVIV||| SVt_PVLV||| SVt_PVMG||| SVt_PVNV||| SVt_PV||| SVt_REGEXP||5.011000| Safefree||| Slab_Alloc||| Slab_Free||| Slab_to_ro||| Slab_to_rw||| StructCopy||| SvCUR_set||| SvCUR||| SvEND||| SvGAMAGIC||5.006001| SvGETMAGIC|5.004050||p SvGROW||| SvIOK_UV||5.006000| SvIOK_notUV||5.006000| SvIOK_off||| SvIOK_only_UV||5.006000| SvIOK_only||| SvIOK_on||| SvIOKp||| SvIOK||| SvIVX||| SvIV_nomg|5.009001||p SvIV_set||| SvIVx||| SvIV||| SvIsCOW_shared_hash||5.008003| SvIsCOW||5.008003| SvLEN_set||| SvLEN||| SvLOCK||5.007003| SvMAGIC_set|5.009003||p SvNIOK_off||| SvNIOKp||| SvNIOK||| SvNOK_off||| SvNOK_only||| SvNOK_on||| SvNOKp||| SvNOK||| SvNVX||| SvNV_nomg||5.013002| SvNV_set||| SvNVx||| SvNV||| SvOK||| SvOOK_offset||5.011000| SvOOK||| SvPOK_off||| SvPOK_only_UTF8||5.006000| SvPOK_only||| SvPOK_on||| SvPOKp||| SvPOK||| SvPVX_const|5.009003||p SvPVX_mutable|5.009003||p SvPVX||| SvPV_const|5.009003||p SvPV_flags_const_nolen|5.009003||p SvPV_flags_const|5.009003||p SvPV_flags_mutable|5.009003||p SvPV_flags|5.007002||p SvPV_force_flags_mutable|5.009003||p SvPV_force_flags_nolen|5.009003||p SvPV_force_flags|5.007002||p SvPV_force_mutable|5.009003||p SvPV_force_nolen|5.009003||p SvPV_force_nomg_nolen|5.009003||p SvPV_force_nomg|5.007002||p SvPV_force|||p SvPV_mutable|5.009003||p SvPV_nolen_const|5.009003||p SvPV_nolen|5.006000||p SvPV_nomg_const_nolen|5.009003||p SvPV_nomg_const|5.009003||p SvPV_nomg_nolen|5.013007||p SvPV_nomg|5.007002||p SvPV_renew|5.009003||p SvPV_set||| SvPVbyte_force||5.009002| SvPVbyte_nolen||5.006000| SvPVbytex_force||5.006000| SvPVbytex||5.006000| SvPVbyte|5.006000||p SvPVutf8_force||5.006000| SvPVutf8_nolen||5.006000| SvPVutf8x_force||5.006000| SvPVutf8x||5.006000| SvPVutf8||5.006000| SvPVx||| SvPV||| SvREFCNT_dec_NN||5.017007| SvREFCNT_dec||| SvREFCNT_inc_NN|5.009004||p SvREFCNT_inc_simple_NN|5.009004||p SvREFCNT_inc_simple_void_NN|5.009004||p SvREFCNT_inc_simple_void|5.009004||p SvREFCNT_inc_simple|5.009004||p SvREFCNT_inc_void_NN|5.009004||p SvREFCNT_inc_void|5.009004||p SvREFCNT_inc|||p SvREFCNT||| SvROK_off||| SvROK_on||| SvROK||| SvRV_set|5.009003||p SvRV||| SvRXOK||5.009005| SvRX||5.009005| SvSETMAGIC||| SvSHARED_HASH|5.009003||p SvSHARE||5.007003| SvSTASH_set|5.009003||p SvSTASH||| SvSetMagicSV_nosteal||5.004000| SvSetMagicSV||5.004000| SvSetSV_nosteal||5.004000| SvSetSV||| SvTAINTED_off||5.004000| SvTAINTED_on||5.004000| SvTAINTED||5.004000| SvTAINT||| SvTHINKFIRST||| SvTRUE_nomg||5.013006| SvTRUE||| SvTYPE||| SvUNLOCK||5.007003| SvUOK|5.007001|5.006000|p SvUPGRADE||| SvUTF8_off||5.006000| SvUTF8_on||5.006000| SvUTF8||5.006000| SvUVXx|5.004000||p SvUVX|5.004000||p SvUV_nomg|5.009001||p SvUV_set|5.009003||p SvUVx|5.004000||p SvUV|5.004000||p SvVOK||5.008001| SvVSTRING_mg|5.009004||p THIS|||n UNDERBAR|5.009002||p UTF8_MAXBYTES|5.009002||p UVSIZE|5.006000||p UVTYPE|5.006000||p UVXf|5.007001||p UVof|5.006000||p UVuf|5.006000||p UVxf|5.006000||p WARN_ALL|5.006000||p WARN_AMBIGUOUS|5.006000||p WARN_ASSERTIONS|5.021008||p WARN_BAREWORD|5.006000||p WARN_CLOSED|5.006000||p WARN_CLOSURE|5.006000||p WARN_DEBUGGING|5.006000||p WARN_DEPRECATED|5.006000||p WARN_DIGIT|5.006000||p WARN_EXEC|5.006000||p WARN_EXITING|5.006000||p WARN_GLOB|5.006000||p WARN_INPLACE|5.006000||p WARN_INTERNAL|5.006000||p WARN_IO|5.006000||p WARN_LAYER|5.008000||p WARN_MALLOC|5.006000||p WARN_MISC|5.006000||p WARN_NEWLINE|5.006000||p WARN_NUMERIC|5.006000||p WARN_ONCE|5.006000||p WARN_OVERFLOW|5.006000||p WARN_PACK|5.006000||p WARN_PARENTHESIS|5.006000||p WARN_PIPE|5.006000||p WARN_PORTABLE|5.006000||p WARN_PRECEDENCE|5.006000||p WARN_PRINTF|5.006000||p WARN_PROTOTYPE|5.006000||p WARN_QW|5.006000||p WARN_RECURSION|5.006000||p WARN_REDEFINE|5.006000||p WARN_REGEXP|5.006000||p WARN_RESERVED|5.006000||p WARN_SEMICOLON|5.006000||p WARN_SEVERE|5.006000||p WARN_SIGNAL|5.006000||p WARN_SUBSTR|5.006000||p WARN_SYNTAX|5.006000||p WARN_TAINT|5.006000||p WARN_THREADS|5.008000||p WARN_UNINITIALIZED|5.006000||p WARN_UNOPENED|5.006000||p WARN_UNPACK|5.006000||p WARN_UNTIE|5.006000||p WARN_UTF8|5.006000||p WARN_VOID|5.006000||p WIDEST_UTYPE|5.015004||p XCPT_CATCH|5.009002||p XCPT_RETHROW|5.009002||p XCPT_TRY_END|5.009002||p XCPT_TRY_START|5.009002||p XPUSHi||| XPUSHmortal|5.009002||p XPUSHn||| XPUSHp||| XPUSHs||| XPUSHu|5.004000||p XSPROTO|5.010000||p XSRETURN_EMPTY||| XSRETURN_IV||| XSRETURN_NO||| XSRETURN_NV||| XSRETURN_PV||| XSRETURN_UNDEF||| XSRETURN_UV|5.008001||p XSRETURN_YES||| XSRETURN|||p XST_mIV||| XST_mNO||| XST_mNV||| XST_mPV||| XST_mUNDEF||| XST_mUV|5.008001||p XST_mYES||| XS_APIVERSION_BOOTCHECK||5.021008| XS_EXTERNAL||5.021008| XS_INTERNAL||5.021008| XS_VERSION_BOOTCHECK||5.021008| XS_VERSION||| XSprePUSH|5.006000||p XS||| XopDISABLE||5.021008| XopENABLE||5.021008| XopENTRYCUSTOM||5.021008| XopENTRY_set||5.021008| XopENTRY||5.021008| XopFLAGS||5.013007| ZeroD|5.009002||p Zero||| _aMY_CXT|5.007003||p _add_range_to_invlist||| _append_range_to_invlist||| _core_swash_init||| _get_encoding||| _get_regclass_nonbitmap_data||| _get_swash_invlist||| _invlist_array_init|||n _invlist_contains_cp|||n _invlist_contents||| _invlist_dump||| _invlist_intersection_maybe_complement_2nd||| _invlist_intersection||| _invlist_invert||| _invlist_len|||n _invlist_populate_swatch|||n _invlist_search|||n _invlist_subtract||| _invlist_union_maybe_complement_2nd||| _invlist_union||| _is_cur_LC_category_utf8||| _is_in_locale_category||5.021001| _is_uni_FOO||5.017008| _is_uni_perl_idcont||5.017008| _is_uni_perl_idstart||5.017007| _is_utf8_FOO||5.017008| _is_utf8_char_slow||5.021001|n _is_utf8_idcont||5.021001| _is_utf8_idstart||5.021001| _is_utf8_mark||5.017008| _is_utf8_perl_idcont||5.017008| _is_utf8_perl_idstart||5.017007| _is_utf8_xidcont||5.021001| _is_utf8_xidstart||5.021001| _load_PL_utf8_foldclosures||| _make_exactf_invlist||| _new_invlist_C_array||| _new_invlist||| _pMY_CXT|5.007003||p _setup_canned_invlist||| _swash_inversion_hash||| _swash_to_invlist||| _to_fold_latin1||| _to_uni_fold_flags||5.014000| _to_upper_title_latin1||| _to_utf8_fold_flags||5.019009| _to_utf8_lower_flags||5.019009| _to_utf8_title_flags||5.019009| _to_utf8_upper_flags||5.019009| aMY_CXT_|5.007003||p aMY_CXT|5.007003||p aTHXR_|5.021008||p aTHXR|5.021008||p aTHX_|5.006000||p aTHX|5.006000||p aassign_common_vars||| add_above_Latin1_folds||| add_cp_to_invlist||| add_data|||n add_multi_match||| add_utf16_textfilter||| adjust_size_and_find_bucket|||n alloc_maybe_populate_EXACT||| alloccopstash||| allocmy||| amagic_call||| amagic_cmp_locale||| amagic_cmp||| amagic_deref_call||5.013007| amagic_i_ncmp||| amagic_is_enabled||| amagic_ncmp||| anonymise_cv_maybe||| any_dup||| ao||| append_utf8_from_native_byte||5.019004|n apply_attrs_my||| apply_attrs_string||5.006001| apply_attrs||| apply||| assert_uft8_cache_coherent||| assignment_type||| atfork_lock||5.007003|n atfork_unlock||5.007003|n av_arylen_p||5.009003| av_clear||| av_create_and_push||5.009005| av_create_and_unshift_one||5.009005| av_delete||5.006000| av_exists||5.006000| av_extend_guts||| av_extend||| av_fetch||| av_fill||| av_iter_p||5.011000| av_len||| av_make||| av_pop||| av_push||| av_reify||| av_shift||| av_store||| av_tindex||5.017009| av_top_index||5.017009| av_undef||| av_unshift||| ax|||n bad_type_gv||| bad_type_pv||| bind_match||| block_end||5.004000| block_gimme||5.004000| block_start||5.004000| blockhook_register||5.013003| boolSV|5.004000||p boot_core_PerlIO||| boot_core_UNIVERSAL||| boot_core_mro||| bytes_cmp_utf8||5.013007| bytes_from_utf8||5.007001| bytes_to_uni|||n bytes_to_utf8||5.006001| call_argv|5.006000||p call_atexit||5.006000| call_list||5.004000| call_method|5.006000||p call_pv|5.006000||p call_sv|5.006000||p caller_cx|5.013005|5.006000|p calloc||5.007002|n cando||| cast_i32||5.006000|n cast_iv||5.006000|n cast_ulong||5.006000|n cast_uv||5.006000|n check_locale_boundary_crossing||| check_type_and_open||| check_uni||| check_utf8_print||| checkcomma||| ckWARN|5.006000||p ck_entersub_args_core||| ck_entersub_args_list||5.013006| ck_entersub_args_proto_or_list||5.013006| ck_entersub_args_proto||5.013006| ck_warner_d||5.011001|v ck_warner||5.011001|v ckwarn_common||| ckwarn_d||5.009003| ckwarn||5.009003| clear_placeholders||| clear_special_blocks||| clone_params_del|||n clone_params_new|||n closest_cop||| cntrl_to_mnemonic|||n compute_EXACTish|||n construct_ahocorasick_from_trie||| cop_fetch_label||5.015001| cop_free||| cop_hints_2hv||5.013007| cop_hints_fetch_pvn||5.013007| cop_hints_fetch_pvs||5.013007| cop_hints_fetch_pv||5.013007| cop_hints_fetch_sv||5.013007| cop_store_label||5.015001| cophh_2hv||5.013007| cophh_copy||5.013007| cophh_delete_pvn||5.013007| cophh_delete_pvs||5.013007| cophh_delete_pv||5.013007| cophh_delete_sv||5.013007| cophh_fetch_pvn||5.013007| cophh_fetch_pvs||5.013007| cophh_fetch_pv||5.013007| cophh_fetch_sv||5.013007| cophh_free||5.013007| cophh_new_empty||5.021008| cophh_store_pvn||5.013007| cophh_store_pvs||5.013007| cophh_store_pv||5.013007| cophh_store_sv||5.013007| core_prototype||| coresub_op||| could_it_be_a_POSIX_class|||n cr_textfilter||| create_eval_scope||| croak_memory_wrap||5.019003|n croak_no_mem|||n croak_no_modify||5.013003|n croak_nocontext|||vn croak_popstack|||n croak_sv||5.013001| croak_xs_usage||5.010001|n croak|||v csighandler||5.009003|n current_re_engine||| curse||| custom_op_desc||5.007003| custom_op_get_field||| custom_op_name||5.007003| custom_op_register||5.013007| custom_op_xop||5.013007| cv_ckproto_len_flags||| cv_clone_into||| cv_clone||| cv_const_sv_or_av|||n cv_const_sv||5.003070|n cv_dump||| cv_forget_slab||| cv_get_call_checker||5.013006| cv_name||5.021005| cv_set_call_checker_flags||5.021004| cv_set_call_checker||5.013006| cv_undef_flags||| cv_undef||| cvgv_from_hek||| cvgv_set||| cvstash_set||| cx_dump||5.005000| cx_dup||| cxinc||| dAXMARK|5.009003||p dAX|5.007002||p dITEMS|5.007002||p dMARK||| dMULTICALL||5.009003| dMY_CXT_SV|5.007003||p dMY_CXT|5.007003||p dNOOP|5.006000||p dORIGMARK||| dSP||| dTHR|5.004050||p dTHXR|5.021008||p dTHXa|5.006000||p dTHXoa|5.006000||p dTHX|5.006000||p dUNDERBAR|5.009002||p dVAR|5.009003||p dXCPT|5.009002||p dXSARGS||| dXSI32||| dXSTARG|5.006000||p deb_curcv||| deb_nocontext|||vn deb_stack_all||| deb_stack_n||| debop||5.005000| debprofdump||5.005000| debprof||| debstackptrs||5.007003| debstack||5.007003| debug_start_match||| deb||5.007003|v defelem_target||| del_sv||| delete_eval_scope||| delimcpy||5.004000|n deprecate_commaless_var_list||| despatch_signals||5.007001| destroy_matcher||| die_nocontext|||vn die_sv||5.013001| die_unwind||| die|||v dirp_dup||| div128||| djSP||| do_aexec5||| do_aexec||| do_aspawn||| do_binmode||5.004050| do_chomp||| do_close||| do_delete_local||| do_dump_pad||| do_eof||| do_exec3||| do_execfree||| do_exec||| do_gv_dump||5.006000| do_gvgv_dump||5.006000| do_hv_dump||5.006000| do_ipcctl||| do_ipcget||| do_join||| do_magic_dump||5.006000| do_msgrcv||| do_msgsnd||| do_ncmp||| do_oddball||| do_op_dump||5.006000| do_open6||| do_open9||5.006000| do_open_raw||| do_openn||5.007001| do_open||5.003070| do_pmop_dump||5.006000| do_print||| do_readline||| do_seek||| do_semop||| do_shmio||| do_smartmatch||| do_spawn_nowait||| do_spawn||| do_sprintf||| do_sv_dump||5.006000| do_sysseek||| do_tell||| do_trans_complex_utf8||| do_trans_complex||| do_trans_count_utf8||| do_trans_count||| do_trans_simple_utf8||| do_trans_simple||| do_trans||| do_vecget||| do_vecset||| do_vop||| docatch||| doeval||| dofile||| dofindlabel||| doform||| doing_taint||5.008001|n dooneliner||| doopen_pm||| doparseform||| dopoptoeval||| dopoptogiven||| dopoptolabel||| dopoptoloop||| dopoptosub_at||| dopoptowhen||| doref||5.009003| dounwind||| dowantarray||| drand48_init_r|||n drand48_r|||n dump_all_perl||| dump_all||5.006000| dump_c_backtrace||| dump_eval||5.006000| dump_exec_pos||| dump_form||5.006000| dump_indent||5.006000|v dump_mstats||| dump_packsubs_perl||| dump_packsubs||5.006000| dump_sub_perl||| dump_sub||5.006000| dump_sv_child||| dump_trie_interim_list||| dump_trie_interim_table||| dump_trie||| dump_vindent||5.006000| dumpuntil||| dup_attrlist||| emulate_cop_io||| eval_pv|5.006000||p eval_sv|5.006000||p exec_failed||| expect_number||| fbm_compile||5.005000| fbm_instr||5.005000| feature_is_enabled||| filter_add||| filter_del||| filter_gets||| filter_read||| finalize_optree||| finalize_op||| find_and_forget_pmops||| find_array_subscript||| find_beginning||| find_byclass||| find_default_stash||| find_hash_subscript||| find_in_my_stash||| find_lexical_cv||| find_runcv_where||| find_runcv||5.008001| find_rundefsv2||| find_rundefsvoffset||5.009002| find_rundefsv||5.013002| find_script||| find_uninit_var||| first_symbol|||n fixup_errno_string||| foldEQ_latin1||5.013008|n foldEQ_locale||5.013002|n foldEQ_utf8_flags||5.013010| foldEQ_utf8||5.013002| foldEQ||5.013002|n fold_constants||| forbid_setid||| force_ident_maybe_lex||| force_ident||| force_list||| force_next||| force_strict_version||| force_version||| force_word||| forget_pmop||| form_nocontext|||vn form_short_octal_warning||| form||5.004000|v fp_dup||| fprintf_nocontext|||vn free_c_backtrace||| free_global_struct||| free_tied_hv_pool||| free_tmps||| gen_constant_list||| get_ANYOF_cp_list_for_ssc||| get_and_check_backslash_N_name||| get_aux_mg||| get_av|5.006000||p get_c_backtrace_dump||| get_c_backtrace||| get_context||5.006000|n get_cvn_flags|5.009005||p get_cvs|5.011000||p get_cv|5.006000||p get_db_sub||| get_debug_opts||| get_hash_seed||| get_hv|5.006000||p get_invlist_iter_addr|||n get_invlist_offset_addr|||n get_invlist_previous_index_addr|||n get_mstats||| get_no_modify||| get_num||| get_op_descs||5.005000| get_op_names||5.005000| get_opargs||| get_ppaddr||5.006000| get_re_arg||| get_sv|5.006000||p get_vtbl||5.005030| getcwd_sv||5.007002| getenv_len||| glob_2number||| glob_assign_glob||| gp_dup||| gp_free||| gp_ref||| grok_atou||5.021004|n grok_bin|5.007003||p grok_bslash_N||| grok_bslash_c||| grok_bslash_o||| grok_bslash_x||| grok_hex|5.007003||p grok_infnan||5.021004|n grok_number_flags||5.021002| grok_number|5.007002||p grok_numeric_radix|5.007002||p grok_oct|5.007003||p group_end||| gv_AVadd||| gv_HVadd||| gv_IOadd||| gv_SVadd||| gv_add_by_type_p||| gv_autoload4||5.004000| gv_autoload_pvn||5.015004| gv_autoload_pv||5.015004| gv_autoload_sv||5.015004| gv_check||| gv_const_sv||5.009003| gv_dump||5.006000| gv_efullname3||5.003070| gv_efullname4||5.006001| gv_efullname||| gv_fetchfile_flags||5.009005| gv_fetchfile||| gv_fetchmeth_autoload||5.007003| gv_fetchmeth_internal||| gv_fetchmeth_pv_autoload||5.015004| gv_fetchmeth_pvn_autoload||5.015004| gv_fetchmeth_pvn||5.015004| gv_fetchmeth_pv||5.015004| gv_fetchmeth_sv_autoload||5.015004| gv_fetchmeth_sv||5.015004| gv_fetchmethod_autoload||5.004000| gv_fetchmethod_pv_flags||5.015004| gv_fetchmethod_pvn_flags||5.015004| gv_fetchmethod_sv_flags||5.015004| gv_fetchmethod||| gv_fetchmeth||| gv_fetchpvn_flags|5.009002||p gv_fetchpvs|5.009004||p gv_fetchpv||| gv_fetchsv|5.009002||p gv_fullname3||5.003070| gv_fullname4||5.006001| gv_fullname||| gv_handler||5.007001| gv_init_pvn||5.015004| gv_init_pv||5.015004| gv_init_svtype||| gv_init_sv||5.015004| gv_init||| gv_is_in_main||| gv_magicalize_isa||| gv_magicalize||| gv_name_set||5.009004| gv_override||| gv_setref||| gv_stashpvn_internal||| gv_stashpvn|5.003070||p gv_stashpvs|5.009003||p gv_stashpv||| gv_stashsvpvn_cached||| gv_stashsv||| gv_try_downgrade||| handle_regex_sets||| he_dup||| hek_dup||| hfree_next_entry||| hfreeentries||| hsplit||| hv_assert||| hv_auxinit_internal|||n hv_auxinit||| hv_backreferences_p||| hv_clear_placeholders||5.009001| hv_clear||| hv_common_key_len||5.010000| hv_common||5.010000| hv_copy_hints_hv||5.009004| hv_delayfree_ent||5.004000| hv_delete_common||| hv_delete_ent||5.003070| hv_delete||| hv_eiter_p||5.009003| hv_eiter_set||5.009003| hv_ename_add||| hv_ename_delete||| hv_exists_ent||5.003070| hv_exists||| hv_fetch_ent||5.003070| hv_fetchs|5.009003||p hv_fetch||| hv_fill||5.013002| hv_free_ent_ret||| hv_free_ent||5.004000| hv_iterinit||| hv_iterkeysv||5.003070| hv_iterkey||| hv_iternext_flags||5.008000| hv_iternextsv||| hv_iternext||| hv_iterval||| hv_kill_backrefs||| hv_ksplit||5.003070| hv_magic_check|||n hv_magic||| hv_name_set||5.009003| hv_notallowed||| hv_placeholders_get||5.009003| hv_placeholders_p||| hv_placeholders_set||5.009003| hv_rand_set||5.018000| hv_riter_p||5.009003| hv_riter_set||5.009003| hv_scalar||5.009001| hv_store_ent||5.003070| hv_store_flags||5.008000| hv_stores|5.009004||p hv_store||| hv_undef_flags||| hv_undef||| ibcmp_locale||5.004000| ibcmp_utf8||5.007003| ibcmp||| incline||| incpush_if_exists||| incpush_use_sep||| incpush||| ingroup||| init_argv_symbols||| init_constants||| init_dbargs||| init_debugger||| init_global_struct||| init_i18nl10n||5.006000| init_i18nl14n||5.006000| init_ids||| init_interp||| init_main_stash||| init_perllib||| init_postdump_symbols||| init_predump_symbols||| init_stacks||5.005000| init_tm||5.007002| inplace_aassign||| instr|||n intro_my||5.004000| intuit_method||| intuit_more||| invert||| invlist_array|||n invlist_clone||| invlist_extend||| invlist_highest|||n invlist_is_iterating|||n invlist_iterfinish|||n invlist_iterinit|||n invlist_iternext|||n invlist_max|||n invlist_previous_index|||n invlist_set_len||| invlist_set_previous_index|||n invlist_trim|||n invoke_exception_hook||| io_close||| isALNUMC|5.006000||p isALNUM_lazy||5.021001| isALPHANUMERIC||5.017008| isALPHA||| isASCII|5.006000||p isBLANK|5.006001||p isCNTRL|5.006000||p isDIGIT||| isFOO_lc||| isFOO_utf8_lc||| isGRAPH|5.006000||p isGV_with_GP|5.009004||p isIDCONT||5.017008| isIDFIRST_lazy||5.021001| isIDFIRST||| isLOWER||| isOCTAL||5.013005| isPRINT|5.004000||p isPSXSPC|5.006001||p isPUNCT|5.006000||p isSPACE||| isUPPER||| isUTF8_CHAR||5.021001| isWORDCHAR||5.013006| isXDIGIT|5.006000||p is_an_int||| is_ascii_string||5.011000| is_handle_constructor|||n is_invariant_string||5.021007|n is_lvalue_sub||5.007001| is_safe_syscall||5.019004| is_ssc_worth_it|||n is_uni_alnum_lc||5.006000| is_uni_alnumc_lc||5.017007| is_uni_alnumc||5.017007| is_uni_alnum||5.006000| is_uni_alpha_lc||5.006000| is_uni_alpha||5.006000| is_uni_ascii_lc||5.006000| is_uni_ascii||5.006000| is_uni_blank_lc||5.017002| is_uni_blank||5.017002| is_uni_cntrl_lc||5.006000| is_uni_cntrl||5.006000| is_uni_digit_lc||5.006000| is_uni_digit||5.006000| is_uni_graph_lc||5.006000| is_uni_graph||5.006000| is_uni_idfirst_lc||5.006000| is_uni_idfirst||5.006000| is_uni_lower_lc||5.006000| is_uni_lower||5.006000| is_uni_print_lc||5.006000| is_uni_print||5.006000| is_uni_punct_lc||5.006000| is_uni_punct||5.006000| is_uni_space_lc||5.006000| is_uni_space||5.006000| is_uni_upper_lc||5.006000| is_uni_upper||5.006000| is_uni_xdigit_lc||5.006000| is_uni_xdigit||5.006000| is_utf8_alnumc||5.017007| is_utf8_alnum||5.006000| is_utf8_alpha||5.006000| is_utf8_ascii||5.006000| is_utf8_blank||5.017002| is_utf8_char_buf||5.015008|n is_utf8_char||5.006000|n is_utf8_cntrl||5.006000| is_utf8_common||| is_utf8_digit||5.006000| is_utf8_graph||5.006000| is_utf8_idcont||5.008000| is_utf8_idfirst||5.006000| is_utf8_lower||5.006000| is_utf8_mark||5.006000| is_utf8_perl_space||5.011001| is_utf8_perl_word||5.011001| is_utf8_posix_digit||5.011001| is_utf8_print||5.006000| is_utf8_punct||5.006000| is_utf8_space||5.006000| is_utf8_string_loclen||5.009003|n is_utf8_string_loc||5.008001|n is_utf8_string||5.006001|n is_utf8_upper||5.006000| is_utf8_xdigit||5.006000| is_utf8_xidcont||5.013010| is_utf8_xidfirst||5.013010| isa_lookup||| isinfnansv||| isinfnan||5.021004|n items|||n ix|||n jmaybe||| join_exact||| keyword_plugin_standard||| keyword||| leave_common||| leave_scope||| lex_bufutf8||5.011002| lex_discard_to||5.011002| lex_grow_linestr||5.011002| lex_next_chunk||5.011002| lex_peek_unichar||5.011002| lex_read_space||5.011002| lex_read_to||5.011002| lex_read_unichar||5.011002| lex_start||5.009005| lex_stuff_pvn||5.011002| lex_stuff_pvs||5.013005| lex_stuff_pv||5.013006| lex_stuff_sv||5.011002| lex_unstuff||5.011002| listkids||| list||| load_module_nocontext|||vn load_module|5.006000||pv localize||| looks_like_bool||| looks_like_number||| lop||| mPUSHi|5.009002||p mPUSHn|5.009002||p mPUSHp|5.009002||p mPUSHs|5.010001||p mPUSHu|5.009002||p mXPUSHi|5.009002||p mXPUSHn|5.009002||p mXPUSHp|5.009002||p mXPUSHs|5.010001||p mXPUSHu|5.009002||p magic_clear_all_env||| magic_cleararylen_p||| magic_clearenv||| magic_clearhints||| magic_clearhint||| magic_clearisa||| magic_clearpack||| magic_clearsig||| magic_copycallchecker||| magic_dump||5.006000| magic_existspack||| magic_freearylen_p||| magic_freeovrld||| magic_getarylen||| magic_getdebugvar||| magic_getdefelem||| magic_getnkeys||| magic_getpack||| magic_getpos||| magic_getsig||| magic_getsubstr||| magic_gettaint||| magic_getuvar||| magic_getvec||| magic_get||| magic_killbackrefs||| magic_methcall1||| magic_methcall|||v magic_methpack||| magic_nextpack||| magic_regdata_cnt||| magic_regdatum_get||| magic_regdatum_set||| magic_scalarpack||| magic_set_all_env||| magic_setarylen||| magic_setcollxfrm||| magic_setdbline||| magic_setdebugvar||| magic_setdefelem||| magic_setenv||| magic_sethint||| magic_setisa||| magic_setlvref||| magic_setmglob||| magic_setnkeys||| magic_setpack||| magic_setpos||| magic_setregexp||| magic_setsig||| magic_setsubstr||| magic_settaint||| magic_setutf8||| magic_setuvar||| magic_setvec||| magic_set||| magic_sizepack||| magic_wipepack||| make_matcher||| make_trie||| malloc_good_size|||n malloced_size|||n malloc||5.007002|n markstack_grow||5.021001| matcher_matches_sv||| maybe_multimagic_gv||| mayberelocate||| measure_struct||| memEQs|5.009005||p memEQ|5.004000||p memNEs|5.009005||p memNE|5.004000||p mem_collxfrm||| mem_log_common|||n mess_alloc||| mess_nocontext|||vn mess_sv||5.013001| mess||5.006000|v mfree||5.007002|n mg_clear||| mg_copy||| mg_dup||| mg_find_mglob||| mg_findext|5.013008||pn mg_find|||n mg_free_type||5.013006| mg_free||| mg_get||| mg_length||5.005000| mg_localize||| mg_magical|||n mg_set||| mg_size||5.005000| mini_mktime||5.007002|n minus_v||| missingterm||| mode_from_discipline||| modkids||| more_bodies||| more_sv||| moreswitches||| move_proto_attr||| mro_clean_isarev||| mro_gather_and_rename||| mro_get_from_name||5.010001| mro_get_linear_isa_dfs||| mro_get_linear_isa||5.009005| mro_get_private_data||5.010001| mro_isa_changed_in||| mro_meta_dup||| mro_meta_init||| mro_method_changed_in||5.009005| mro_package_moved||| mro_register||5.010001| mro_set_mro||5.010001| mro_set_private_data||5.010001| mul128||| mulexp10|||n my_atof2||5.007002| my_atof||5.006000| my_attrs||| my_bcopy|||n my_bzero|||n my_chsize||| my_clearenv||| my_cxt_index||| my_cxt_init||| my_dirfd||5.009005|n my_exit_jump||| my_exit||| my_failure_exit||5.004000| my_fflush_all||5.006000| my_fork||5.007003|n my_kid||| my_lstat_flags||| my_lstat||5.021008| my_memcmp|||n my_memset|||n my_pclose||5.003070| my_popen_list||5.007001| my_popen||5.003070| my_setenv||| my_setlocale||| my_snprintf|5.009004||pvn my_socketpair||5.007003|n my_sprintf|5.009003||pvn my_stat_flags||| my_stat||5.021008| my_strerror||5.021001| my_strftime||5.007002| my_strlcat|5.009004||pn my_strlcpy|5.009004||pn my_unexec||| my_vsnprintf||5.009004|n need_utf8|||n newANONATTRSUB||5.006000| newANONHASH||| newANONLIST||| newANONSUB||| newASSIGNOP||| newATTRSUB_x||| newATTRSUB||5.006000| newAVREF||| newAV||| newBINOP||| newCONDOP||| newCONSTSUB_flags||5.015006| newCONSTSUB|5.004050||p newCVREF||| newDEFSVOP||5.021006| newFORM||| newFOROP||5.013007| newGIVENOP||5.009003| newGIVWHENOP||| newGP||| newGVOP||| newGVREF||| newGVgen_flags||5.015004| newGVgen||| newHVREF||| newHVhv||5.005000| newHV||| newIO||| newLISTOP||| newLOGOP||| newLOOPEX||| newLOOPOP||| newMETHOP_internal||| newMETHOP_named||5.021005| newMETHOP||5.021005| newMYSUB||5.017004| newNULLLIST||| newOP||| newPADNAMELIST||5.021007|n newPADNAMEouter||5.021007|n newPADNAMEpvn||5.021007|n newPADOP||| newPMOP||| newPROG||| newPVOP||| newRANGE||| newRV_inc|5.004000||p newRV_noinc|5.004000||p newRV||| newSLICEOP||| newSTATEOP||| newSTUB||| newSUB||| newSVOP||| newSVREF||| newSV_type|5.009005||p newSVavdefelem||| newSVhek||5.009003| newSViv||| newSVnv||| newSVpadname||5.017004| newSVpv_share||5.013006| newSVpvf_nocontext|||vn newSVpvf||5.004000|v newSVpvn_flags|5.010001||p newSVpvn_share|5.007001||p newSVpvn_utf8|5.010001||p newSVpvn|5.004050||p newSVpvs_flags|5.010001||p newSVpvs_share|5.009003||p newSVpvs|5.009003||p newSVpv||| newSVrv||| newSVsv||| newSVuv|5.006000||p newSV||| newUNOP_AUX||5.021007| newUNOP||| newWHENOP||5.009003| newWHILEOP||5.013007| newXS_deffile||| newXS_flags||5.009004| newXS_len_flags||| newXSproto||5.006000| newXS||5.006000| new_collate||5.006000| new_constant||| new_ctype||5.006000| new_he||| new_logop||| new_numeric||5.006000| new_stackinfo||5.005000| new_version||5.009000| new_warnings_bitfield||| next_symbol||| nextargv||| nextchar||| ninstr|||n no_bareword_allowed||| no_fh_allowed||| no_op||| noperl_die|||vn not_a_number||| not_incrementable||| nothreadhook||5.008000| nuke_stacks||| num_overflow|||n oopsAV||| oopsHV||| op_append_elem||5.013006| op_append_list||5.013006| op_clear||| op_contextualize||5.013006| op_convert_list||5.021006| op_dump||5.006000| op_free||| op_integerize||| op_linklist||5.013006| op_lvalue_flags||| op_lvalue||5.013007| op_null||5.007002| op_parent||5.021002|n op_prepend_elem||5.013006| op_refcnt_dec||| op_refcnt_inc||| op_refcnt_lock||5.009002| op_refcnt_unlock||5.009002| op_relocate_sv||| op_scope||5.013007| op_sibling_splice||5.021002|n op_std_init||| op_unscope||| open_script||| openn_cleanup||| openn_setup||| opmethod_stash||| opslab_force_free||| opslab_free_nopad||| opslab_free||| pMY_CXT_|5.007003||p pMY_CXT|5.007003||p pTHX_|5.006000||p pTHX|5.006000||p packWARN|5.007003||p pack_cat||5.007003| pack_rec||| package_version||| package||| packlist||5.008001| pad_add_anon||5.008001| pad_add_name_pvn||5.015001| pad_add_name_pvs||5.015001| pad_add_name_pv||5.015001| pad_add_name_sv||5.015001| pad_add_weakref||| pad_alloc_name||| pad_alloc||| pad_block_start||| pad_check_dup||| pad_compname_type||5.009003| pad_findlex||| pad_findmy_pvn||5.015001| pad_findmy_pvs||5.015001| pad_findmy_pv||5.015001| pad_findmy_sv||5.015001| pad_fixup_inner_anons||| pad_free||| pad_leavemy||| pad_new||5.008001| pad_push||| pad_reset||| pad_setsv||| pad_sv||| pad_swipe||| pad_tidy||5.008001| padlist_dup||| padlist_store||| padname_dup||| padname_free||| padnamelist_dup||| padnamelist_fetch||5.021007|n padnamelist_free||| padnamelist_store||5.021007| parse_arithexpr||5.013008| parse_barestmt||5.013007| parse_block||5.013007| parse_body||| parse_fullexpr||5.013008| parse_fullstmt||5.013005| parse_gv_stash_name||| parse_ident||| parse_label||5.013007| parse_listexpr||5.013008| parse_lparen_question_flags||| parse_stmtseq||5.013006| parse_subsignature||| parse_termexpr||5.013008| parse_unicode_opts||| parser_dup||| parser_free_nexttoke_ops||| parser_free||| path_is_searchable|||n peep||| pending_ident||| perl_alloc_using|||n perl_alloc|||n perl_clone_using|||n perl_clone|||n perl_construct|||n perl_destruct||5.007003|n perl_free|||n perl_parse||5.006000|n perl_run|||n pidgone||| pm_description||| pmop_dump||5.006000| pmruntime||| pmtrans||| pop_scope||| populate_ANYOF_from_invlist||| populate_isa|||v pregcomp||5.009005| pregexec||| pregfree2||5.011000| pregfree||| prescan_version||5.011004| printbuf||| printf_nocontext|||vn process_special_blocks||| ptr_hash|||n ptr_table_clear||5.009005| ptr_table_fetch||5.009005| ptr_table_find|||n ptr_table_free||5.009005| ptr_table_new||5.009005| ptr_table_split||5.009005| ptr_table_store||5.009005| push_scope||| put_charclass_bitmap_innards||| put_code_point||| put_range||| pv_display|5.006000||p pv_escape|5.009004||p pv_pretty|5.009004||p pv_uni_display||5.007003| qerror||| qsortsvu||| quadmath_format_needed|||n quadmath_format_single|||n re_compile||5.009005| re_croak2||| re_dup_guts||| re_intuit_start||5.019001| re_intuit_string||5.006000| re_op_compile||| realloc||5.007002|n reentrant_free||5.021008| reentrant_init||5.021008| reentrant_retry||5.021008|vn reentrant_size||5.021008| ref_array_or_hash||| refcounted_he_chain_2hv||| refcounted_he_fetch_pvn||| refcounted_he_fetch_pvs||| refcounted_he_fetch_pv||| refcounted_he_fetch_sv||| refcounted_he_free||| refcounted_he_inc||| refcounted_he_new_pvn||| refcounted_he_new_pvs||| refcounted_he_new_pv||| refcounted_he_new_sv||| refcounted_he_value||| refkids||| refto||| ref||5.021008| reg2Lanode||| reg_check_named_buff_matched|||n reg_named_buff_all||5.009005| reg_named_buff_exists||5.009005| reg_named_buff_fetch||5.009005| reg_named_buff_firstkey||5.009005| reg_named_buff_iter||| reg_named_buff_nextkey||5.009005| reg_named_buff_scalar||5.009005| reg_named_buff||| reg_node||| reg_numbered_buff_fetch||| reg_numbered_buff_length||| reg_numbered_buff_store||| reg_qr_package||| reg_recode||| reg_scan_name||| reg_skipcomment|||n reg_temp_copy||| reganode||| regatom||| regbranch||| regclass_swash||5.009004| regclass||| regcppop||| regcppush||| regcurly|||n regdump_extflags||| regdump_intflags||| regdump||5.005000| regdupe_internal||| regexec_flags||5.005000| regfree_internal||5.009005| reghop3|||n reghop4|||n reghopmaybe3|||n reginclass||| reginitcolors||5.006000| reginsert||| regmatch||| regnext||5.005000| regnode_guts||| regpatws|||n regpiece||| regpposixcc||| regprop||| regrepeat||| regtail_study||| regtail||| regtry||| reg||| repeatcpy|||n report_evil_fh||| report_redefined_cv||| report_uninit||| report_wrongway_fh||| require_pv||5.006000| require_tie_mod||| restore_magic||| rninstr|||n rpeep||| rsignal_restore||| rsignal_save||| rsignal_state||5.004000| rsignal||5.004000| run_body||| run_user_filter||| runops_debug||5.005000| runops_standard||5.005000| rv2cv_op_cv||5.013006| rvpv_dup||| rxres_free||| rxres_restore||| rxres_save||| safesyscalloc||5.006000|n safesysfree||5.006000|n safesysmalloc||5.006000|n safesysrealloc||5.006000|n same_dirent||| save_I16||5.004000| save_I32||| save_I8||5.006000| save_adelete||5.011000| save_aelem_flags||5.011000| save_aelem||5.004050| save_aliased_sv||| save_alloc||5.006000| save_aptr||| save_ary||| save_bool||5.008001| save_clearsv||| save_delete||| save_destructor_x||5.006000| save_destructor||5.006000| save_freeop||| save_freepv||| save_freesv||| save_generic_pvref||5.006001| save_generic_svref||5.005030| save_gp||5.004000| save_hash||| save_hdelete||5.011000| save_hek_flags|||n save_helem_flags||5.011000| save_helem||5.004050| save_hints||5.010001| save_hptr||| save_int||| save_item||| save_iv||5.005000| save_lines||| save_list||| save_long||| save_magic_flags||| save_mortalizesv||5.007001| save_nogv||| save_op||5.005000| save_padsv_and_mortalize||5.010001| save_pptr||| save_pushi32ptr||5.010001| save_pushptri32ptr||| save_pushptrptr||5.010001| save_pushptr||5.010001| save_re_context||5.006000| save_scalar_at||| save_scalar||| save_set_svflags||5.009000| save_shared_pvref||5.007003| save_sptr||| save_strlen||| save_svref||| save_vptr||5.006000| savepvn||| savepvs||5.009003| savepv||| savesharedpvn||5.009005| savesharedpvs||5.013006| savesharedpv||5.007003| savesharedsvpv||5.013006| savestack_grow_cnt||5.008001| savestack_grow||| savesvpv||5.009002| sawparens||| scalar_mod_type|||n scalarboolean||| scalarkids||| scalarseq||| scalarvoid||| scalar||| scan_bin||5.006000| scan_commit||| scan_const||| scan_formline||| scan_heredoc||| scan_hex||| scan_ident||| scan_inputsymbol||| scan_num||5.007001| scan_oct||| scan_pat||| scan_str||| scan_subst||| scan_trans||| scan_version||5.009001| scan_vstring||5.009005| scan_word||| search_const||| seed||5.008001| sequence_num||| set_ANYOF_arg||| set_caret_X||| set_context||5.006000|n set_numeric_local||5.006000| set_numeric_radix||5.006000| set_numeric_standard||5.006000| set_padlist|||n setdefout||| share_hek_flags||| share_hek||5.004000| should_warn_nl|||n si_dup||| sighandler|||n simplify_sort||| skipspace_flags||| softref2xv||| sortcv_stacked||| sortcv_xsub||| sortcv||| sortsv_flags||5.009003| sortsv||5.007003| space_join_names_mortal||| ss_dup||| ssc_add_range||| ssc_and||| ssc_anything||| ssc_clear_locale|||n ssc_cp_and||| ssc_finalize||| ssc_init||| ssc_intersection||| ssc_is_anything|||n ssc_is_cp_posixl_init|||n ssc_or||| ssc_union||| stack_grow||| start_glob||| start_subparse||5.004000| stdize_locale||| strEQ||| strGE||| strGT||| strLE||| strLT||| strNE||| str_to_version||5.006000| strip_return||| strnEQ||| strnNE||| study_chunk||| sub_crush_depth||| sublex_done||| sublex_push||| sublex_start||| sv_2bool_flags||5.013006| sv_2bool||| sv_2cv||| sv_2io||| sv_2iuv_common||| sv_2iuv_non_preserve||| sv_2iv_flags||5.009001| sv_2iv||| sv_2mortal||| sv_2num||| sv_2nv_flags||5.013001| sv_2pv_flags|5.007002||p sv_2pv_nolen|5.006000||p sv_2pvbyte_nolen|5.006000||p sv_2pvbyte|5.006000||p sv_2pvutf8_nolen||5.006000| sv_2pvutf8||5.006000| sv_2pv||| sv_2uv_flags||5.009001| sv_2uv|5.004000||p sv_add_arena||| sv_add_backref||| sv_backoff|||n sv_bless||| sv_buf_to_ro||| sv_buf_to_rw||| sv_cat_decode||5.008001| sv_catpv_flags||5.013006| sv_catpv_mg|5.004050||p sv_catpv_nomg||5.013006| sv_catpvf_mg_nocontext|||pvn sv_catpvf_mg|5.006000|5.004000|pv sv_catpvf_nocontext|||vn sv_catpvf||5.004000|v sv_catpvn_flags||5.007002| sv_catpvn_mg|5.004050||p sv_catpvn_nomg|5.007002||p sv_catpvn||| sv_catpvs_flags||5.013006| sv_catpvs_mg||5.013006| sv_catpvs_nomg||5.013006| sv_catpvs|5.009003||p sv_catpv||| sv_catsv_flags||5.007002| sv_catsv_mg|5.004050||p sv_catsv_nomg|5.007002||p sv_catsv||| sv_chop||| sv_clean_all||| sv_clean_objs||| sv_clear||| sv_cmp_flags||5.013006| sv_cmp_locale_flags||5.013006| sv_cmp_locale||5.004000| sv_cmp||| sv_collxfrm_flags||5.013006| sv_collxfrm||| sv_copypv_flags||5.017002| sv_copypv_nomg||5.017002| sv_copypv||| sv_dec_nomg||5.013002| sv_dec||| sv_del_backref||| sv_derived_from_pvn||5.015004| sv_derived_from_pv||5.015004| sv_derived_from_sv||5.015004| sv_derived_from||5.004000| sv_destroyable||5.010000| sv_display||| sv_does_pvn||5.015004| sv_does_pv||5.015004| sv_does_sv||5.015004| sv_does||5.009004| sv_dump||| sv_dup_common||| sv_dup_inc_multiple||| sv_dup_inc||| sv_dup||| sv_eq_flags||5.013006| sv_eq||| sv_exp_grow||| sv_force_normal_flags||5.007001| sv_force_normal||5.006000| sv_free2||| sv_free_arenas||| sv_free||| sv_get_backrefs||5.021008| sv_gets||5.003070| sv_grow||| sv_i_ncmp||| sv_inc_nomg||5.013002| sv_inc||| sv_insert_flags||5.010001| sv_insert||| sv_isa||| sv_isobject||| sv_iv||5.005000| sv_kill_backrefs||| sv_len_utf8_nomg||| sv_len_utf8||5.006000| sv_len||| sv_magic_portable|5.021008|5.004000|p sv_magicext_mglob||| sv_magicext||5.007003| sv_magic||| sv_mortalcopy_flags||| sv_mortalcopy||| sv_ncmp||| sv_newmortal||| sv_newref||| sv_nolocking||5.007003| sv_nosharing||5.007003| sv_nounlocking||| sv_nv||5.005000| sv_or_pv_pos_u2b||| sv_peek||5.005000| sv_pos_b2u_flags||5.019003| sv_pos_b2u_midway||| sv_pos_b2u||5.006000| sv_pos_u2b_cached||| sv_pos_u2b_flags||5.011005| sv_pos_u2b_forwards|||n sv_pos_u2b_midway|||n sv_pos_u2b||5.006000| sv_pvbyten_force||5.006000| sv_pvbyten||5.006000| sv_pvbyte||5.006000| sv_pvn_force_flags|5.007002||p sv_pvn_force||| sv_pvn_nomg|5.007003|5.005000|p sv_pvn||5.005000| sv_pvutf8n_force||5.006000| sv_pvutf8n||5.006000| sv_pvutf8||5.006000| sv_pv||5.006000| sv_recode_to_utf8||5.007003| sv_reftype||| sv_ref||| sv_release_COW||| sv_replace||| sv_report_used||| sv_resetpvn||| sv_reset||| sv_rvweaken||5.006000| sv_sethek||| sv_setiv_mg|5.004050||p sv_setiv||| sv_setnv_mg|5.006000||p sv_setnv||| sv_setpv_mg|5.004050||p sv_setpvf_mg_nocontext|||pvn sv_setpvf_mg|5.006000|5.004000|pv sv_setpvf_nocontext|||vn sv_setpvf||5.004000|v sv_setpviv_mg||5.008001| sv_setpviv||5.008001| sv_setpvn_mg|5.004050||p sv_setpvn||| sv_setpvs_mg||5.013006| sv_setpvs|5.009004||p sv_setpv||| sv_setref_iv||| sv_setref_nv||| sv_setref_pvn||| sv_setref_pvs||5.021008| sv_setref_pv||| sv_setref_uv||5.007001| sv_setsv_cow||| sv_setsv_flags||5.007002| sv_setsv_mg|5.004050||p sv_setsv_nomg|5.007002||p sv_setsv||| sv_setuv_mg|5.004050||p sv_setuv|5.004000||p sv_tainted||5.004000| sv_taint||5.004000| sv_true||5.005000| sv_unglob||| sv_uni_display||5.007003| sv_unmagicext|5.013008||p sv_unmagic||| sv_unref_flags||5.007001| sv_unref||| sv_untaint||5.004000| sv_upgrade||| sv_usepvn_flags||5.009004| sv_usepvn_mg|5.004050||p sv_usepvn||| sv_utf8_decode||5.006000| sv_utf8_downgrade||5.006000| sv_utf8_encode||5.006000| sv_utf8_upgrade_flags_grow||5.011000| sv_utf8_upgrade_flags||5.007002| sv_utf8_upgrade_nomg||5.007002| sv_utf8_upgrade||5.007001| sv_uv|5.005000||p sv_vcatpvf_mg|5.006000|5.004000|p sv_vcatpvfn_flags||5.017002| sv_vcatpvfn||5.004000| sv_vcatpvf|5.006000|5.004000|p sv_vsetpvf_mg|5.006000|5.004000|p sv_vsetpvfn||5.004000| sv_vsetpvf|5.006000|5.004000|p svtype||| swallow_bom||| swash_fetch||5.007002| swash_init||5.006000| swash_scan_list_line||| swatch_get||| sync_locale||5.021004| sys_init3||5.010000|n sys_init||5.010000|n sys_intern_clear||| sys_intern_dup||| sys_intern_init||| sys_term||5.010000|n taint_env||| taint_proper||| tied_method|||v tmps_grow_p||| toFOLD_uni||5.007003| toFOLD_utf8||5.019001| toFOLD||5.019001| toLOWER_L1||5.019001| toLOWER_LC||5.004000| toLOWER_uni||5.007003| toLOWER_utf8||5.015007| toLOWER||| toTITLE_uni||5.007003| toTITLE_utf8||5.015007| toTITLE||5.019001| toUPPER_uni||5.007003| toUPPER_utf8||5.015007| toUPPER||| to_byte_substr||| to_lower_latin1|||n to_uni_fold||5.007003| to_uni_lower_lc||5.006000| to_uni_lower||5.007003| to_uni_title_lc||5.006000| to_uni_title||5.007003| to_uni_upper_lc||5.006000| to_uni_upper||5.007003| to_utf8_case||5.007003| to_utf8_fold||5.015007| to_utf8_lower||5.015007| to_utf8_substr||| to_utf8_title||5.015007| to_utf8_upper||5.015007| tokenize_use||| tokeq||| tokereport||| too_few_arguments_pv||| too_many_arguments_pv||| translate_substr_offsets|||n try_amagic_bin||| try_amagic_un||| uiv_2buf|||n unlnk||| unop_aux_stringify||| unpack_rec||| unpack_str||5.007003| unpackstring||5.008001| unreferenced_to_tmp_stack||| unshare_hek_or_pvn||| unshare_hek||| unsharepvn||5.003070| unwind_handler_stack||| update_debugger_info||| upg_version||5.009005| usage||| utf16_textfilter||| utf16_to_utf8_reversed||5.006001| utf16_to_utf8||5.006001| utf8_distance||5.006000| utf8_hop||5.006000|n utf8_length||5.007001| utf8_mg_len_cache_update||| utf8_mg_pos_cache_update||| utf8_to_bytes||5.006001| utf8_to_uvchr_buf||5.015009| utf8_to_uvchr||5.007001| utf8_to_uvuni_buf||5.015009| utf8_to_uvuni||5.007001| utf8n_to_uvchr||5.007001| utf8n_to_uvuni||5.007001| utilize||| uvchr_to_utf8_flags||5.007003| uvchr_to_utf8||5.007001| uvoffuni_to_utf8_flags||5.019004| uvuni_to_utf8_flags||5.007003| uvuni_to_utf8||5.007001| valid_utf8_to_uvchr||5.015009| valid_utf8_to_uvuni||5.015009| validate_proto||| validate_suid||| varname||| vcmp||5.009000| vcroak||5.006000| vdeb||5.007003| vform||5.006000| visit||| vivify_defelem||| vivify_ref||| vload_module|5.006000||p vmess||5.006000| vnewSVpvf|5.006000|5.004000|p vnormal||5.009002| vnumify||5.009000| vstringify||5.009000| vverify||5.009003| vwarner||5.006000| vwarn||5.006000| wait4pid||| warn_nocontext|||vn warn_sv||5.013001| warner_nocontext|||vn warner|5.006000|5.004000|pv warn|||v was_lvalue_sub||| watch||| whichsig_pvn||5.015004| whichsig_pv||5.015004| whichsig_sv||5.015004| whichsig||| win32_croak_not_implemented|||n with_queued_errors||| wrap_op_checker||5.015008| write_to_stderr||| xs_boot_epilog||| xs_handshake|||vn xs_version_bootcheck||| yyerror_pvn||| yyerror_pv||| yyerror||| yylex||| yyparse||| yyunlex||| yywarn||| ); if (exists $opt{'list-unsupported'}) { my $f; for $f (sort { lc $a cmp lc $b } keys %API) { next unless $API{$f}{todo}; print "$f ", '.'x(40-length($f)), " ", format_version($API{$f}{todo}), "\n"; } exit 0; } # Scan for possible replacement candidates my(%replace, %need, %hints, %warnings, %depends); my $replace = 0; my($hint, $define, $function); sub find_api { my $code = shift; $code =~ s{ / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]*) | "[^"\\]*(?:\\.[^"\\]*)*" | '[^'\\]*(?:\\.[^'\\]*)*' }{}egsx; grep { exists $API{$_} } $code =~ /(\w+)/mg; } while () { if ($hint) { my $h = $hint->[0] eq 'Hint' ? \%hints : \%warnings; if (m{^\s*\*\s(.*?)\s*$}) { for (@{$hint->[1]}) { $h->{$_} ||= ''; # suppress warning with older perls $h->{$_} .= "$1\n"; } } else { undef $hint } } $hint = [$1, [split /,?\s+/, $2]] if m{^\s*$rccs\s+(Hint|Warning):\s+(\w+(?:,?\s+\w+)*)\s*$}; if ($define) { if ($define->[1] =~ /\\$/) { $define->[1] .= $_; } else { if (exists $API{$define->[0]} && $define->[1] !~ /^DPPP_\(/) { my @n = find_api($define->[1]); push @{$depends{$define->[0]}}, @n if @n } undef $define; } } $define = [$1, $2] if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(.*)}; if ($function) { if (/^}/) { if (exists $API{$function->[0]}) { my @n = find_api($function->[1]); push @{$depends{$function->[0]}}, @n if @n } undef $function; } else { $function->[1] .= $_; } } $function = [$1, ''] if m{^DPPP_\(my_(\w+)\)}; $replace = $1 if m{^\s*$rccs\s+Replace:\s+(\d+)\s+$rcce\s*$}; $replace{$2} = $1 if $replace and m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+)}; $replace{$2} = $1 if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+).*$rccs\s+Replace\s+$rcce}; $replace{$1} = $2 if m{^\s*$rccs\s+Replace (\w+) with (\w+)\s+$rcce\s*$}; if (m{^\s*$rccs\s+(\w+(\s*,\s*\w+)*)\s+depends\s+on\s+(\w+(\s*,\s*\w+)*)\s+$rcce\s*$}) { my @deps = map { s/\s+//g; $_ } split /,/, $3; my $d; for $d (map { s/\s+//g; $_ } split /,/, $1) { push @{$depends{$d}}, @deps; } } $need{$1} = 1 if m{^#if\s+defined\(NEED_(\w+)(?:_GLOBAL)?\)}; } for (values %depends) { my %s; $_ = [sort grep !$s{$_}++, @$_]; } if (exists $opt{'api-info'}) { my $f; my $count = 0; my $match = $opt{'api-info'} =~ m!^/(.*)/$! ? $1 : "^\Q$opt{'api-info'}\E\$"; for $f (sort { lc $a cmp lc $b } keys %API) { next unless $f =~ /$match/; print "\n=== $f ===\n\n"; my $info = 0; if ($API{$f}{base} || $API{$f}{todo}) { my $base = format_version($API{$f}{base} || $API{$f}{todo}); print "Supported at least starting from perl-$base.\n"; $info++; } if ($API{$f}{provided}) { my $todo = $API{$f}{todo} ? format_version($API{$f}{todo}) : "5.003"; print "Support by $ppport provided back to perl-$todo.\n"; print "Support needs to be explicitly requested by NEED_$f.\n" if exists $need{$f}; print "Depends on: ", join(', ', @{$depends{$f}}), ".\n" if exists $depends{$f}; print "\n$hints{$f}" if exists $hints{$f}; print "\nWARNING:\n$warnings{$f}" if exists $warnings{$f}; $info++; } print "No portability information available.\n" unless $info; $count++; } $count or print "Found no API matching '$opt{'api-info'}'."; print "\n"; exit 0; } if (exists $opt{'list-provided'}) { my $f; for $f (sort { lc $a cmp lc $b } keys %API) { next unless $API{$f}{provided}; my @flags; push @flags, 'explicit' if exists $need{$f}; push @flags, 'depend' if exists $depends{$f}; push @flags, 'hint' if exists $hints{$f}; push @flags, 'warning' if exists $warnings{$f}; my $flags = @flags ? ' ['.join(', ', @flags).']' : ''; print "$f$flags\n"; } exit 0; } my @files; my @srcext = qw( .xs .c .h .cc .cpp -c.inc -xs.inc ); my $srcext = join '|', map { quotemeta $_ } @srcext; if (@ARGV) { my %seen; for (@ARGV) { if (-e) { if (-f) { push @files, $_ unless $seen{$_}++; } else { warn "'$_' is not a file.\n" } } else { my @new = grep { -f } glob $_ or warn "'$_' does not exist.\n"; push @files, grep { !$seen{$_}++ } @new; } } } else { eval { require File::Find; File::Find::find(sub { $File::Find::name =~ /($srcext)$/i and push @files, $File::Find::name; }, '.'); }; if ($@) { @files = map { glob "*$_" } @srcext; } } if (!@ARGV || $opt{filter}) { my(@in, @out); my %xsc = map { /(.*)\.xs$/ ? ("$1.c" => 1, "$1.cc" => 1) : () } @files; for (@files) { my $out = exists $xsc{$_} || /\b\Q$ppport\E$/i || !/($srcext)$/i; push @{ $out ? \@out : \@in }, $_; } if (@ARGV && @out) { warning("Skipping the following files (use --nofilter to avoid this):\n| ", join "\n| ", @out); } @files = @in; } die "No input files given!\n" unless @files; my(%files, %global, %revreplace); %revreplace = reverse %replace; my $filename; my $patch_opened = 0; for $filename (@files) { unless (open IN, "<$filename") { warn "Unable to read from $filename: $!\n"; next; } info("Scanning $filename ..."); my $c = do { local $/; }; close IN; my %file = (orig => $c, changes => 0); # Temporarily remove C/XS comments and strings from the code my @ccom; $c =~ s{ ( ^$HS*\#$HS*include\b[^\r\n]+\b(?:\Q$ppport\E|XSUB\.h)\b[^\r\n]* | ^$HS*\#$HS*(?:define|elif|if(?:def)?)\b[^\r\n]* ) | ( ^$HS*\#[^\r\n]* | "[^"\\]*(?:\\.[^"\\]*)*" | '[^'\\]*(?:\\.[^'\\]*)*' | / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]* ) ) }{ defined $2 and push @ccom, $2; defined $1 ? $1 : "$ccs$#ccom$cce" }mgsex; $file{ccom} = \@ccom; $file{code} = $c; $file{has_inc_ppport} = $c =~ /^$HS*#$HS*include[^\r\n]+\b\Q$ppport\E\b/m; my $func; for $func (keys %API) { my $match = $func; $match .= "|$revreplace{$func}" if exists $revreplace{$func}; if ($c =~ /\b(?:Perl_)?($match)\b/) { $file{uses_replace}{$1}++ if exists $revreplace{$func} && $1 eq $revreplace{$func}; $file{uses_Perl}{$func}++ if $c =~ /\bPerl_$func\b/; if (exists $API{$func}{provided}) { $file{uses_provided}{$func}++; if (!exists $API{$func}{base} || $API{$func}{base} > $opt{'compat-version'}) { $file{uses}{$func}++; my @deps = rec_depend($func); if (@deps) { $file{uses_deps}{$func} = \@deps; for (@deps) { $file{uses}{$_} = 0 unless exists $file{uses}{$_}; } } for ($func, @deps) { $file{needs}{$_} = 'static' if exists $need{$_}; } } } if (exists $API{$func}{todo} && $API{$func}{todo} > $opt{'compat-version'}) { if ($c =~ /\b$func\b/) { $file{uses_todo}{$func}++; } } } } while ($c =~ /^$HS*#$HS*define$HS+(NEED_(\w+?)(_GLOBAL)?)\b/mg) { if (exists $need{$2}) { $file{defined $3 ? 'needed_global' : 'needed_static'}{$2}++; } else { warning("Possibly wrong #define $1 in $filename") } } for (qw(uses needs uses_todo needed_global needed_static)) { for $func (keys %{$file{$_}}) { push @{$global{$_}{$func}}, $filename; } } $files{$filename} = \%file; } # Globally resolve NEED_'s my $need; for $need (keys %{$global{needs}}) { if (@{$global{needs}{$need}} > 1) { my @targets = @{$global{needs}{$need}}; my @t = grep $files{$_}{needed_global}{$need}, @targets; @targets = @t if @t; @t = grep /\.xs$/i, @targets; @targets = @t if @t; my $target = shift @targets; $files{$target}{needs}{$need} = 'global'; for (@{$global{needs}{$need}}) { $files{$_}{needs}{$need} = 'extern' if $_ ne $target; } } } for $filename (@files) { exists $files{$filename} or next; info("=== Analyzing $filename ==="); my %file = %{$files{$filename}}; my $func; my $c = $file{code}; my $warnings = 0; for $func (sort keys %{$file{uses_Perl}}) { if ($API{$func}{varargs}) { unless ($API{$func}{nothxarg}) { my $changes = ($c =~ s{\b(Perl_$func\s*\(\s*)(?!aTHX_?)(\)|[^\s)]*\))} { $1 . ($2 eq ')' ? 'aTHX' : 'aTHX_ ') . $2 }ge); if ($changes) { warning("Doesn't pass interpreter argument aTHX to Perl_$func"); $file{changes} += $changes; } } } else { warning("Uses Perl_$func instead of $func"); $file{changes} += ($c =~ s{\bPerl_$func(\s*)\((\s*aTHX_?)?\s*} {$func$1(}g); } } for $func (sort keys %{$file{uses_replace}}) { warning("Uses $func instead of $replace{$func}"); $file{changes} += ($c =~ s/\b$func\b/$replace{$func}/g); } for $func (sort keys %{$file{uses_provided}}) { if ($file{uses}{$func}) { if (exists $file{uses_deps}{$func}) { diag("Uses $func, which depends on ", join(', ', @{$file{uses_deps}{$func}})); } else { diag("Uses $func"); } } $warnings += hint($func); } unless ($opt{quiet}) { for $func (sort keys %{$file{uses_todo}}) { print "*** WARNING: Uses $func, which may not be portable below perl ", format_version($API{$func}{todo}), ", even with '$ppport'\n"; $warnings++; } } for $func (sort keys %{$file{needed_static}}) { my $message = ''; if (not exists $file{uses}{$func}) { $message = "No need to define NEED_$func if $func is never used"; } elsif (exists $file{needs}{$func} && $file{needs}{$func} ne 'static') { $message = "No need to define NEED_$func when already needed globally"; } if ($message) { diag($message); $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_$func\b.*$LF//mg); } } for $func (sort keys %{$file{needed_global}}) { my $message = ''; if (not exists $global{uses}{$func}) { $message = "No need to define NEED_${func}_GLOBAL if $func is never used"; } elsif (exists $file{needs}{$func}) { if ($file{needs}{$func} eq 'extern') { $message = "No need to define NEED_${func}_GLOBAL when already needed globally"; } elsif ($file{needs}{$func} eq 'static') { $message = "No need to define NEED_${func}_GLOBAL when only used in this file"; } } if ($message) { diag($message); $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_${func}_GLOBAL\b.*$LF//mg); } } $file{needs_inc_ppport} = keys %{$file{uses}}; if ($file{needs_inc_ppport}) { my $pp = ''; for $func (sort keys %{$file{needs}}) { my $type = $file{needs}{$func}; next if $type eq 'extern'; my $suffix = $type eq 'global' ? '_GLOBAL' : ''; unless (exists $file{"needed_$type"}{$func}) { if ($type eq 'global') { diag("Files [@{$global{needs}{$func}}] need $func, adding global request"); } else { diag("File needs $func, adding static request"); } $pp .= "#define NEED_$func$suffix\n"; } } if ($pp && ($c =~ s/^(?=$HS*#$HS*define$HS+NEED_\w+)/$pp/m)) { $pp = ''; $file{changes}++; } unless ($file{has_inc_ppport}) { diag("Needs to include '$ppport'"); $pp .= qq(#include "$ppport"\n) } if ($pp) { $file{changes} += ($c =~ s/^($HS*#$HS*define$HS+NEED_\w+.*?)^/$1$pp/ms) || ($c =~ s/^(?=$HS*#$HS*include.*\Q$ppport\E)/$pp/m) || ($c =~ s/^($HS*#$HS*include.*XSUB.*\s*?)^/$1$pp/m) || ($c =~ s/^/$pp/); } } else { if ($file{has_inc_ppport}) { diag("No need to include '$ppport'"); $file{changes} += ($c =~ s/^$HS*?#$HS*include.*\Q$ppport\E.*?$LF//m); } } # put back in our C comments my $ix; my $cppc = 0; my @ccom = @{$file{ccom}}; for $ix (0 .. $#ccom) { if (!$opt{cplusplus} && $ccom[$ix] =~ s!^//!!) { $cppc++; $file{changes} += $c =~ s/$rccs$ix$rcce/$ccs$ccom[$ix] $cce/; } else { $c =~ s/$rccs$ix$rcce/$ccom[$ix]/; } } if ($cppc) { my $s = $cppc != 1 ? 's' : ''; warning("Uses $cppc C++ style comment$s, which is not portable"); } my $s = $warnings != 1 ? 's' : ''; my $warn = $warnings ? " ($warnings warning$s)" : ''; info("Analysis completed$warn"); if ($file{changes}) { if (exists $opt{copy}) { my $newfile = "$filename$opt{copy}"; if (-e $newfile) { error("'$newfile' already exists, refusing to write copy of '$filename'"); } else { local *F; if (open F, ">$newfile") { info("Writing copy of '$filename' with changes to '$newfile'"); print F $c; close F; } else { error("Cannot open '$newfile' for writing: $!"); } } } elsif (exists $opt{patch} || $opt{changes}) { if (exists $opt{patch}) { unless ($patch_opened) { if (open PATCH, ">$opt{patch}") { $patch_opened = 1; } else { error("Cannot open '$opt{patch}' for writing: $!"); delete $opt{patch}; $opt{changes} = 1; goto fallback; } } mydiff(\*PATCH, $filename, $c); } else { fallback: info("Suggested changes:"); mydiff(\*STDOUT, $filename, $c); } } else { my $s = $file{changes} == 1 ? '' : 's'; info("$file{changes} potentially required change$s detected"); } } else { info("Looks good"); } } close PATCH if $patch_opened; exit 0; sub try_use { eval "use @_;"; return $@ eq '' } sub mydiff { local *F = shift; my($file, $str) = @_; my $diff; if (exists $opt{diff}) { $diff = run_diff($opt{diff}, $file, $str); } if (!defined $diff and try_use('Text::Diff')) { $diff = Text::Diff::diff($file, \$str, { STYLE => 'Unified' }); $diff = <
$tmp") { print F $str; close F; if (open F, "$prog $file $tmp |") { while () { s/\Q$tmp\E/$file.patched/; $diff .= $_; } close F; unlink $tmp; return $diff; } unlink $tmp; } else { error("Cannot open '$tmp' for writing: $!"); } return undef; } sub rec_depend { my($func, $seen) = @_; return () unless exists $depends{$func}; $seen = {%{$seen||{}}}; return () if $seen->{$func}++; my %s; grep !$s{$_}++, map { ($_, rec_depend($_, $seen)) } @{$depends{$func}}; } sub parse_version { my $ver = shift; if ($ver =~ /^(\d+)\.(\d+)\.(\d+)$/) { return ($1, $2, $3); } elsif ($ver !~ /^\d+\.[\d_]+$/) { die "cannot parse version '$ver'\n"; } $ver =~ s/_//g; $ver =~ s/$/000000/; my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/; $v = int $v; $s = int $s; if ($r < 5 || ($r == 5 && $v < 6)) { if ($s % 10) { die "cannot parse version '$ver'\n"; } } return ($r, $v, $s); } sub format_version { my $ver = shift; $ver =~ s/$/000000/; my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/; $v = int $v; $s = int $s; if ($r < 5 || ($r == 5 && $v < 6)) { if ($s % 10) { die "invalid version '$ver'\n"; } $s /= 10; $ver = sprintf "%d.%03d", $r, $v; $s > 0 and $ver .= sprintf "_%02d", $s; return $ver; } return sprintf "%d.%d.%d", $r, $v, $s; } sub info { $opt{quiet} and return; print @_, "\n"; } sub diag { $opt{quiet} and return; $opt{diag} and print @_, "\n"; } sub warning { $opt{quiet} and return; print "*** ", @_, "\n"; } sub error { print "*** ERROR: ", @_, "\n"; } my %given_hints; my %given_warnings; sub hint { $opt{quiet} and return; my $func = shift; my $rv = 0; if (exists $warnings{$func} && !$given_warnings{$func}++) { my $warn = $warnings{$func}; $warn =~ s!^!*** !mg; print "*** WARNING: $func\n", $warn; $rv++; } if ($opt{hints} && exists $hints{$func} && !$given_hints{$func}++) { my $hint = $hints{$func}; $hint =~ s/^/ /mg; print " --- hint for $func ---\n", $hint; } $rv; } sub usage { my($usage) = do { local(@ARGV,$/)=($0); <> } =~ /^=head\d$HS+SYNOPSIS\s*^(.*?)\s*^=/ms; my %M = ( 'I' => '*' ); $usage =~ s/^\s*perl\s+\S+/$^X $0/; $usage =~ s/([A-Z])<([^>]+)>/$M{$1}$2$M{$1}/g; print < }; my($copy) = $self =~ /^=head\d\s+COPYRIGHT\s*^(.*?)^=\w+/ms; $copy =~ s/^(?=\S+)/ /gms; $self =~ s/^$HS+Do NOT edit.*?(?=^-)/$copy/ms; $self =~ s/^SKIP.*(?=^__DATA__)/SKIP if (\@ARGV && \$ARGV[0] eq '--unstrip') { eval { require Devel::PPPort }; \$@ and die "Cannot require Devel::PPPort, please install.\\n"; if (eval \$Devel::PPPort::VERSION < $VERSION) { die "$0 was originally generated with Devel::PPPort $VERSION.\\n" . "Your Devel::PPPort is only version \$Devel::PPPort::VERSION.\\n" . "Please install a newer version, or --unstrip will not work.\\n"; } Devel::PPPort::WriteFile(\$0); exit 0; } print <$0" or die "cannot strip $0: $!\n"; print OUT "$pl$c\n"; exit 0; } __DATA__ */ #ifndef _P_P_PORTABILITY_H_ #define _P_P_PORTABILITY_H_ #ifndef DPPP_NAMESPACE # define DPPP_NAMESPACE DPPP_ #endif #define DPPP_CAT2(x,y) CAT2(x,y) #define DPPP_(name) DPPP_CAT2(DPPP_NAMESPACE, name) #ifndef PERL_REVISION # if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION)) # define PERL_PATCHLEVEL_H_IMPLICIT # include # endif # if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL))) # include # endif # ifndef PERL_REVISION # define PERL_REVISION (5) /* Replace: 1 */ # define PERL_VERSION PATCHLEVEL # define PERL_SUBVERSION SUBVERSION /* Replace PERL_PATCHLEVEL with PERL_VERSION */ /* Replace: 0 */ # endif #endif #define _dpppDEC2BCD(dec) ((((dec)/100)<<8)|((((dec)%100)/10)<<4)|((dec)%10)) #define PERL_BCDVERSION ((_dpppDEC2BCD(PERL_REVISION)<<24)|(_dpppDEC2BCD(PERL_VERSION)<<12)|_dpppDEC2BCD(PERL_SUBVERSION)) /* It is very unlikely that anyone will try to use this with Perl 6 (or greater), but who knows. */ #if PERL_REVISION != 5 # error ppport.h only works with Perl version 5 #endif /* PERL_REVISION != 5 */ #ifndef dTHR # define dTHR dNOOP #endif #ifndef dTHX # define dTHX dNOOP #endif #ifndef dTHXa # define dTHXa(x) dNOOP #endif #ifndef pTHX # define pTHX void #endif #ifndef pTHX_ # define pTHX_ #endif #ifndef aTHX # define aTHX #endif #ifndef aTHX_ # define aTHX_ #endif #if (PERL_BCDVERSION < 0x5006000) # ifdef USE_THREADS # define aTHXR thr # define aTHXR_ thr, # else # define aTHXR # define aTHXR_ # endif # define dTHXR dTHR #else # define aTHXR aTHX # define aTHXR_ aTHX_ # define dTHXR dTHX #endif #ifndef dTHXoa # define dTHXoa(x) dTHXa(x) #endif #ifdef I_LIMITS # include #endif #ifndef PERL_UCHAR_MIN # define PERL_UCHAR_MIN ((unsigned char)0) #endif #ifndef PERL_UCHAR_MAX # ifdef UCHAR_MAX # define PERL_UCHAR_MAX ((unsigned char)UCHAR_MAX) # else # ifdef MAXUCHAR # define PERL_UCHAR_MAX ((unsigned char)MAXUCHAR) # else # define PERL_UCHAR_MAX ((unsigned char)~(unsigned)0) # endif # endif #endif #ifndef PERL_USHORT_MIN # define PERL_USHORT_MIN ((unsigned short)0) #endif #ifndef PERL_USHORT_MAX # ifdef USHORT_MAX # define PERL_USHORT_MAX ((unsigned short)USHORT_MAX) # else # ifdef MAXUSHORT # define PERL_USHORT_MAX ((unsigned short)MAXUSHORT) # else # ifdef USHRT_MAX # define PERL_USHORT_MAX ((unsigned short)USHRT_MAX) # else # define PERL_USHORT_MAX ((unsigned short)~(unsigned)0) # endif # endif # endif #endif #ifndef PERL_SHORT_MAX # ifdef SHORT_MAX # define PERL_SHORT_MAX ((short)SHORT_MAX) # else # ifdef MAXSHORT /* Often used in */ # define PERL_SHORT_MAX ((short)MAXSHORT) # else # ifdef SHRT_MAX # define PERL_SHORT_MAX ((short)SHRT_MAX) # else # define PERL_SHORT_MAX ((short) (PERL_USHORT_MAX >> 1)) # endif # endif # endif #endif #ifndef PERL_SHORT_MIN # ifdef SHORT_MIN # define PERL_SHORT_MIN ((short)SHORT_MIN) # else # ifdef MINSHORT # define PERL_SHORT_MIN ((short)MINSHORT) # else # ifdef SHRT_MIN # define PERL_SHORT_MIN ((short)SHRT_MIN) # else # define PERL_SHORT_MIN (-PERL_SHORT_MAX - ((3 & -1) == 3)) # endif # endif # endif #endif #ifndef PERL_UINT_MAX # ifdef UINT_MAX # define PERL_UINT_MAX ((unsigned int)UINT_MAX) # else # ifdef MAXUINT # define PERL_UINT_MAX ((unsigned int)MAXUINT) # else # define PERL_UINT_MAX (~(unsigned int)0) # endif # endif #endif #ifndef PERL_UINT_MIN # define PERL_UINT_MIN ((unsigned int)0) #endif #ifndef PERL_INT_MAX # ifdef INT_MAX # define PERL_INT_MAX ((int)INT_MAX) # else # ifdef MAXINT /* Often used in */ # define PERL_INT_MAX ((int)MAXINT) # else # define PERL_INT_MAX ((int)(PERL_UINT_MAX >> 1)) # endif # endif #endif #ifndef PERL_INT_MIN # ifdef INT_MIN # define PERL_INT_MIN ((int)INT_MIN) # else # ifdef MININT # define PERL_INT_MIN ((int)MININT) # else # define PERL_INT_MIN (-PERL_INT_MAX - ((3 & -1) == 3)) # endif # endif #endif #ifndef PERL_ULONG_MAX # ifdef ULONG_MAX # define PERL_ULONG_MAX ((unsigned long)ULONG_MAX) # else # ifdef MAXULONG # define PERL_ULONG_MAX ((unsigned long)MAXULONG) # else # define PERL_ULONG_MAX (~(unsigned long)0) # endif # endif #endif #ifndef PERL_ULONG_MIN # define PERL_ULONG_MIN ((unsigned long)0L) #endif #ifndef PERL_LONG_MAX # ifdef LONG_MAX # define PERL_LONG_MAX ((long)LONG_MAX) # else # ifdef MAXLONG # define PERL_LONG_MAX ((long)MAXLONG) # else # define PERL_LONG_MAX ((long) (PERL_ULONG_MAX >> 1)) # endif # endif #endif #ifndef PERL_LONG_MIN # ifdef LONG_MIN # define PERL_LONG_MIN ((long)LONG_MIN) # else # ifdef MINLONG # define PERL_LONG_MIN ((long)MINLONG) # else # define PERL_LONG_MIN (-PERL_LONG_MAX - ((3 & -1) == 3)) # endif # endif #endif #if defined(HAS_QUAD) && (defined(convex) || defined(uts)) # ifndef PERL_UQUAD_MAX # ifdef ULONGLONG_MAX # define PERL_UQUAD_MAX ((unsigned long long)ULONGLONG_MAX) # else # ifdef MAXULONGLONG # define PERL_UQUAD_MAX ((unsigned long long)MAXULONGLONG) # else # define PERL_UQUAD_MAX (~(unsigned long long)0) # endif # endif # endif # ifndef PERL_UQUAD_MIN # define PERL_UQUAD_MIN ((unsigned long long)0L) # endif # ifndef PERL_QUAD_MAX # ifdef LONGLONG_MAX # define PERL_QUAD_MAX ((long long)LONGLONG_MAX) # else # ifdef MAXLONGLONG # define PERL_QUAD_MAX ((long long)MAXLONGLONG) # else # define PERL_QUAD_MAX ((long long) (PERL_UQUAD_MAX >> 1)) # endif # endif # endif # ifndef PERL_QUAD_MIN # ifdef LONGLONG_MIN # define PERL_QUAD_MIN ((long long)LONGLONG_MIN) # else # ifdef MINLONGLONG # define PERL_QUAD_MIN ((long long)MINLONGLONG) # else # define PERL_QUAD_MIN (-PERL_QUAD_MAX - ((3 & -1) == 3)) # endif # endif # endif #endif /* This is based on code from 5.003 perl.h */ #ifdef HAS_QUAD # ifdef cray #ifndef IVTYPE # define IVTYPE int #endif #ifndef IV_MIN # define IV_MIN PERL_INT_MIN #endif #ifndef IV_MAX # define IV_MAX PERL_INT_MAX #endif #ifndef UV_MIN # define UV_MIN PERL_UINT_MIN #endif #ifndef UV_MAX # define UV_MAX PERL_UINT_MAX #endif # ifdef INTSIZE #ifndef IVSIZE # define IVSIZE INTSIZE #endif # endif # else # if defined(convex) || defined(uts) #ifndef IVTYPE # define IVTYPE long long #endif #ifndef IV_MIN # define IV_MIN PERL_QUAD_MIN #endif #ifndef IV_MAX # define IV_MAX PERL_QUAD_MAX #endif #ifndef UV_MIN # define UV_MIN PERL_UQUAD_MIN #endif #ifndef UV_MAX # define UV_MAX PERL_UQUAD_MAX #endif # ifdef LONGLONGSIZE #ifndef IVSIZE # define IVSIZE LONGLONGSIZE #endif # endif # else #ifndef IVTYPE # define IVTYPE long #endif #ifndef IV_MIN # define IV_MIN PERL_LONG_MIN #endif #ifndef IV_MAX # define IV_MAX PERL_LONG_MAX #endif #ifndef UV_MIN # define UV_MIN PERL_ULONG_MIN #endif #ifndef UV_MAX # define UV_MAX PERL_ULONG_MAX #endif # ifdef LONGSIZE #ifndef IVSIZE # define IVSIZE LONGSIZE #endif # endif # endif # endif #ifndef IVSIZE # define IVSIZE 8 #endif #ifndef LONGSIZE # define LONGSIZE 8 #endif #ifndef PERL_QUAD_MIN # define PERL_QUAD_MIN IV_MIN #endif #ifndef PERL_QUAD_MAX # define PERL_QUAD_MAX IV_MAX #endif #ifndef PERL_UQUAD_MIN # define PERL_UQUAD_MIN UV_MIN #endif #ifndef PERL_UQUAD_MAX # define PERL_UQUAD_MAX UV_MAX #endif #else #ifndef IVTYPE # define IVTYPE long #endif #ifndef LONGSIZE # define LONGSIZE 4 #endif #ifndef IV_MIN # define IV_MIN PERL_LONG_MIN #endif #ifndef IV_MAX # define IV_MAX PERL_LONG_MAX #endif #ifndef UV_MIN # define UV_MIN PERL_ULONG_MIN #endif #ifndef UV_MAX # define UV_MAX PERL_ULONG_MAX #endif #endif #ifndef IVSIZE # ifdef LONGSIZE # define IVSIZE LONGSIZE # else # define IVSIZE 4 /* A bold guess, but the best we can make. */ # endif #endif #ifndef UVTYPE # define UVTYPE unsigned IVTYPE #endif #ifndef UVSIZE # define UVSIZE IVSIZE #endif #ifndef sv_setuv # define sv_setuv(sv, uv) \ STMT_START { \ UV TeMpUv = uv; \ if (TeMpUv <= IV_MAX) \ sv_setiv(sv, TeMpUv); \ else \ sv_setnv(sv, (double)TeMpUv); \ } STMT_END #endif #ifndef newSVuv # define newSVuv(uv) ((uv) <= IV_MAX ? newSViv((IV)uv) : newSVnv((NV)uv)) #endif #ifndef sv_2uv # define sv_2uv(sv) ((PL_Sv = (sv)), (UV) (SvNOK(PL_Sv) ? SvNV(PL_Sv) : sv_2nv(PL_Sv))) #endif #ifndef SvUVX # define SvUVX(sv) ((UV)SvIVX(sv)) #endif #ifndef SvUVXx # define SvUVXx(sv) SvUVX(sv) #endif #ifndef SvUV # define SvUV(sv) (SvIOK(sv) ? SvUVX(sv) : sv_2uv(sv)) #endif #ifndef SvUVx # define SvUVx(sv) ((PL_Sv = (sv)), SvUV(PL_Sv)) #endif /* Hint: sv_uv * Always use the SvUVx() macro instead of sv_uv(). */ #ifndef sv_uv # define sv_uv(sv) SvUVx(sv) #endif #if !defined(SvUOK) && defined(SvIOK_UV) # define SvUOK(sv) SvIOK_UV(sv) #endif #ifndef XST_mUV # define XST_mUV(i,v) (ST(i) = sv_2mortal(newSVuv(v)) ) #endif #ifndef XSRETURN_UV # define XSRETURN_UV(v) STMT_START { XST_mUV(0,v); XSRETURN(1); } STMT_END #endif #ifndef PUSHu # define PUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); PUSHTARG; } STMT_END #endif #ifndef XPUSHu # define XPUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); XPUSHTARG; } STMT_END #endif #ifdef HAS_MEMCMP #ifndef memNE # define memNE(s1,s2,l) (memcmp(s1,s2,l)) #endif #ifndef memEQ # define memEQ(s1,s2,l) (!memcmp(s1,s2,l)) #endif #else #ifndef memNE # define memNE(s1,s2,l) (bcmp(s1,s2,l)) #endif #ifndef memEQ # define memEQ(s1,s2,l) (!bcmp(s1,s2,l)) #endif #endif #ifndef memEQs # define memEQs(s1, l, s2) \ (sizeof(s2)-1 == l && memEQ(s1, (s2 ""), (sizeof(s2)-1))) #endif #ifndef memNEs # define memNEs(s1, l, s2) !memEQs(s1, l, s2) #endif #ifndef MoveD # define MoveD(s,d,n,t) memmove((char*)(d),(char*)(s), (n) * sizeof(t)) #endif #ifndef CopyD # define CopyD(s,d,n,t) memcpy((char*)(d),(char*)(s), (n) * sizeof(t)) #endif #ifdef HAS_MEMSET #ifndef ZeroD # define ZeroD(d,n,t) memzero((char*)(d), (n) * sizeof(t)) #endif #else #ifndef ZeroD # define ZeroD(d,n,t) ((void)memzero((char*)(d), (n) * sizeof(t)), d) #endif #endif #ifndef PoisonWith # define PoisonWith(d,n,t,b) (void)memset((char*)(d), (U8)(b), (n) * sizeof(t)) #endif #ifndef PoisonNew # define PoisonNew(d,n,t) PoisonWith(d,n,t,0xAB) #endif #ifndef PoisonFree # define PoisonFree(d,n,t) PoisonWith(d,n,t,0xEF) #endif #ifndef Poison # define Poison(d,n,t) PoisonFree(d,n,t) #endif #ifndef Newx # define Newx(v,n,t) New(0,v,n,t) #endif #ifndef Newxc # define Newxc(v,n,t,c) Newc(0,v,n,t,c) #endif #ifndef Newxz # define Newxz(v,n,t) Newz(0,v,n,t) #endif #ifndef PERL_UNUSED_DECL # ifdef HASATTRIBUTE # if (defined(__GNUC__) && defined(__cplusplus)) || defined(__INTEL_COMPILER) # define PERL_UNUSED_DECL # else # define PERL_UNUSED_DECL __attribute__((unused)) # endif # else # define PERL_UNUSED_DECL # endif #endif #ifndef PERL_UNUSED_ARG # if defined(lint) && defined(S_SPLINT_S) /* www.splint.org */ # include # define PERL_UNUSED_ARG(x) NOTE(ARGUNUSED(x)) # else # define PERL_UNUSED_ARG(x) ((void)x) # endif #endif #ifndef PERL_UNUSED_VAR # define PERL_UNUSED_VAR(x) ((void)x) #endif #ifndef PERL_UNUSED_CONTEXT # ifdef USE_ITHREADS # define PERL_UNUSED_CONTEXT PERL_UNUSED_ARG(my_perl) # else # define PERL_UNUSED_CONTEXT # endif #endif #ifndef NOOP # define NOOP /*EMPTY*/(void)0 #endif #ifndef dNOOP # define dNOOP extern int /*@unused@*/ Perl___notused PERL_UNUSED_DECL #endif #ifndef NVTYPE # if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) # define NVTYPE long double # else # define NVTYPE double # endif typedef NVTYPE NV; #endif #ifndef INT2PTR # if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE) # define PTRV UV # define INT2PTR(any,d) (any)(d) # else # if PTRSIZE == LONGSIZE # define PTRV unsigned long # else # define PTRV unsigned # endif # define INT2PTR(any,d) (any)(PTRV)(d) # endif #endif #ifndef PTR2ul # if PTRSIZE == LONGSIZE # define PTR2ul(p) (unsigned long)(p) # else # define PTR2ul(p) INT2PTR(unsigned long,p) # endif #endif #ifndef PTR2nat # define PTR2nat(p) (PTRV)(p) #endif #ifndef NUM2PTR # define NUM2PTR(any,d) (any)PTR2nat(d) #endif #ifndef PTR2IV # define PTR2IV(p) INT2PTR(IV,p) #endif #ifndef PTR2UV # define PTR2UV(p) INT2PTR(UV,p) #endif #ifndef PTR2NV # define PTR2NV(p) NUM2PTR(NV,p) #endif #undef START_EXTERN_C #undef END_EXTERN_C #undef EXTERN_C #ifdef __cplusplus # define START_EXTERN_C extern "C" { # define END_EXTERN_C } # define EXTERN_C extern "C" #else # define START_EXTERN_C # define END_EXTERN_C # define EXTERN_C extern #endif #if defined(PERL_GCC_PEDANTIC) # ifndef PERL_GCC_BRACE_GROUPS_FORBIDDEN # define PERL_GCC_BRACE_GROUPS_FORBIDDEN # endif #endif #if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) && !defined(__cplusplus) # ifndef PERL_USE_GCC_BRACE_GROUPS # define PERL_USE_GCC_BRACE_GROUPS # endif #endif #undef STMT_START #undef STMT_END #ifdef PERL_USE_GCC_BRACE_GROUPS # define STMT_START (void)( /* gcc supports ``({ STATEMENTS; })'' */ # define STMT_END ) #else # if defined(VOIDFLAGS) && (VOIDFLAGS) && (defined(sun) || defined(__sun__)) && !defined(__GNUC__) # define STMT_START if (1) # define STMT_END else (void)0 # else # define STMT_START do # define STMT_END while (0) # endif #endif #ifndef boolSV # define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no) #endif /* DEFSV appears first in 5.004_56 */ #ifndef DEFSV # define DEFSV GvSV(PL_defgv) #endif #ifndef SAVE_DEFSV # define SAVE_DEFSV SAVESPTR(GvSV(PL_defgv)) #endif #ifndef DEFSV_set # define DEFSV_set(sv) (DEFSV = (sv)) #endif /* Older perls (<=5.003) lack AvFILLp */ #ifndef AvFILLp # define AvFILLp AvFILL #endif #ifndef ERRSV # define ERRSV get_sv("@",FALSE) #endif /* Hint: gv_stashpvn * This function's backport doesn't support the length parameter, but * rather ignores it. Portability can only be ensured if the length * parameter is used for speed reasons, but the length can always be * correctly computed from the string argument. */ #ifndef gv_stashpvn # define gv_stashpvn(str,len,create) gv_stashpv(str,create) #endif /* Replace: 1 */ #ifndef get_cv # define get_cv perl_get_cv #endif #ifndef get_sv # define get_sv perl_get_sv #endif #ifndef get_av # define get_av perl_get_av #endif #ifndef get_hv # define get_hv perl_get_hv #endif /* Replace: 0 */ #ifndef dUNDERBAR # define dUNDERBAR dNOOP #endif #ifndef UNDERBAR # define UNDERBAR DEFSV #endif #ifndef dAX # define dAX I32 ax = MARK - PL_stack_base + 1 #endif #ifndef dITEMS # define dITEMS I32 items = SP - MARK #endif #ifndef dXSTARG # define dXSTARG SV * targ = sv_newmortal() #endif #ifndef dAXMARK # define dAXMARK I32 ax = POPMARK; \ register SV ** const mark = PL_stack_base + ax++ #endif #ifndef XSprePUSH # define XSprePUSH (sp = PL_stack_base + ax - 1) #endif #if (PERL_BCDVERSION < 0x5005000) # undef XSRETURN # define XSRETURN(off) \ STMT_START { \ PL_stack_sp = PL_stack_base + ax + ((off) - 1); \ return; \ } STMT_END #endif #ifndef XSPROTO # define XSPROTO(name) void name(pTHX_ CV* cv) #endif #ifndef SVfARG # define SVfARG(p) ((void*)(p)) #endif #ifndef PERL_ABS # define PERL_ABS(x) ((x) < 0 ? -(x) : (x)) #endif #ifndef dVAR # define dVAR dNOOP #endif #ifndef SVf # define SVf "_" #endif #ifndef UTF8_MAXBYTES # define UTF8_MAXBYTES UTF8_MAXLEN #endif #ifndef CPERLscope # define CPERLscope(x) x #endif #ifndef PERL_HASH # define PERL_HASH(hash,str,len) \ STMT_START { \ const char *s_PeRlHaSh = str; \ I32 i_PeRlHaSh = len; \ U32 hash_PeRlHaSh = 0; \ while (i_PeRlHaSh--) \ hash_PeRlHaSh = hash_PeRlHaSh * 33 + *s_PeRlHaSh++; \ (hash) = hash_PeRlHaSh; \ } STMT_END #endif #ifndef PERLIO_FUNCS_DECL # ifdef PERLIO_FUNCS_CONST # define PERLIO_FUNCS_DECL(funcs) const PerlIO_funcs funcs # define PERLIO_FUNCS_CAST(funcs) (PerlIO_funcs*)(funcs) # else # define PERLIO_FUNCS_DECL(funcs) PerlIO_funcs funcs # define PERLIO_FUNCS_CAST(funcs) (funcs) # endif #endif /* provide these typedefs for older perls */ #if (PERL_BCDVERSION < 0x5009003) # ifdef ARGSproto typedef OP* (CPERLscope(*Perl_ppaddr_t))(ARGSproto); # else typedef OP* (CPERLscope(*Perl_ppaddr_t))(pTHX); # endif typedef OP* (CPERLscope(*Perl_check_t)) (pTHX_ OP*); #endif #ifndef isPSXSPC # define isPSXSPC(c) (isSPACE(c) || (c) == '\v') #endif #ifndef isBLANK # define isBLANK(c) ((c) == ' ' || (c) == '\t') #endif #ifdef EBCDIC #ifndef isALNUMC # define isALNUMC(c) isalnum(c) #endif #ifndef isASCII # define isASCII(c) isascii(c) #endif #ifndef isCNTRL # define isCNTRL(c) iscntrl(c) #endif #ifndef isGRAPH # define isGRAPH(c) isgraph(c) #endif #ifndef isPRINT # define isPRINT(c) isprint(c) #endif #ifndef isPUNCT # define isPUNCT(c) ispunct(c) #endif #ifndef isXDIGIT # define isXDIGIT(c) isxdigit(c) #endif #else # if (PERL_BCDVERSION < 0x5010000) /* Hint: isPRINT * The implementation in older perl versions includes all of the * isSPACE() characters, which is wrong. The version provided by * Devel::PPPort always overrides a present buggy version. */ # undef isPRINT # endif #ifdef HAS_QUAD # ifdef U64TYPE # define WIDEST_UTYPE U64TYPE # else # define WIDEST_UTYPE Quad_t # endif #else # define WIDEST_UTYPE U32 #endif #ifndef isALNUMC # define isALNUMC(c) (isALPHA(c) || isDIGIT(c)) #endif #ifndef isASCII # define isASCII(c) ((WIDEST_UTYPE) (c) <= 127) #endif #ifndef isCNTRL # define isCNTRL(c) ((WIDEST_UTYPE) (c) < ' ' || (c) == 127) #endif #ifndef isGRAPH # define isGRAPH(c) (isALNUM(c) || isPUNCT(c)) #endif #ifndef isPRINT # define isPRINT(c) (((c) >= 32 && (c) < 127)) #endif #ifndef isPUNCT # define isPUNCT(c) (((c) >= 33 && (c) <= 47) || ((c) >= 58 && (c) <= 64) || ((c) >= 91 && (c) <= 96) || ((c) >= 123 && (c) <= 126)) #endif #ifndef isXDIGIT # define isXDIGIT(c) (isDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) #endif #endif /* Until we figure out how to support this in older perls... */ #if (PERL_BCDVERSION >= 0x5008000) #ifndef HeUTF8 # define HeUTF8(he) ((HeKLEN(he) == HEf_SVKEY) ? \ SvUTF8(HeKEY_sv(he)) : \ (U32)HeKUTF8(he)) #endif #endif #ifndef PERL_SIGNALS_UNSAFE_FLAG #define PERL_SIGNALS_UNSAFE_FLAG 0x0001 #if (PERL_BCDVERSION < 0x5008000) # define D_PPP_PERL_SIGNALS_INIT PERL_SIGNALS_UNSAFE_FLAG #else # define D_PPP_PERL_SIGNALS_INIT 0 #endif #if defined(NEED_PL_signals) static U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT; #elif defined(NEED_PL_signals_GLOBAL) U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT; #else extern U32 DPPP_(my_PL_signals); #endif #define PL_signals DPPP_(my_PL_signals) #endif /* Hint: PL_ppaddr * Calling an op via PL_ppaddr requires passing a context argument * for threaded builds. Since the context argument is different for * 5.005 perls, you can use aTHXR (supplied by ppport.h), which will * automatically be defined as the correct argument. */ #if (PERL_BCDVERSION <= 0x5005005) /* Replace: 1 */ # define PL_ppaddr ppaddr # define PL_no_modify no_modify /* Replace: 0 */ #endif #if (PERL_BCDVERSION <= 0x5004005) /* Replace: 1 */ # define PL_DBsignal DBsignal # define PL_DBsingle DBsingle # define PL_DBsub DBsub # define PL_DBtrace DBtrace # define PL_Sv Sv # define PL_bufend bufend # define PL_bufptr bufptr # define PL_compiling compiling # define PL_copline copline # define PL_curcop curcop # define PL_curstash curstash # define PL_debstash debstash # define PL_defgv defgv # define PL_diehook diehook # define PL_dirty dirty # define PL_dowarn dowarn # define PL_errgv errgv # define PL_error_count error_count # define PL_expect expect # define PL_hexdigit hexdigit # define PL_hints hints # define PL_in_my in_my # define PL_laststatval laststatval # define PL_lex_state lex_state # define PL_lex_stuff lex_stuff # define PL_linestr linestr # define PL_na na # define PL_perl_destruct_level perl_destruct_level # define PL_perldb perldb # define PL_rsfp_filters rsfp_filters # define PL_rsfp rsfp # define PL_stack_base stack_base # define PL_stack_sp stack_sp # define PL_statcache statcache # define PL_stdingv stdingv # define PL_sv_arenaroot sv_arenaroot # define PL_sv_no sv_no # define PL_sv_undef sv_undef # define PL_sv_yes sv_yes # define PL_tainted tainted # define PL_tainting tainting # define PL_tokenbuf tokenbuf /* Replace: 0 */ #endif /* Warning: PL_parser * For perl versions earlier than 5.9.5, this is an always * non-NULL dummy. Also, it cannot be dereferenced. Don't * use it if you can avoid is and unless you absolutely know * what you're doing. * If you always check that PL_parser is non-NULL, you can * define DPPP_PL_parser_NO_DUMMY to avoid the creation of * a dummy parser structure. */ #if (PERL_BCDVERSION >= 0x5009005) # ifdef DPPP_PL_parser_NO_DUMMY # define D_PPP_my_PL_parser_var(var) ((PL_parser ? PL_parser : \ (croak("panic: PL_parser == NULL in %s:%d", \ __FILE__, __LINE__), (yy_parser *) NULL))->var) # else # ifdef DPPP_PL_parser_NO_DUMMY_WARNING # define D_PPP_parser_dummy_warning(var) # else # define D_PPP_parser_dummy_warning(var) \ warn("warning: dummy PL_" #var " used in %s:%d", __FILE__, __LINE__), # endif # define D_PPP_my_PL_parser_var(var) ((PL_parser ? PL_parser : \ (D_PPP_parser_dummy_warning(var) &DPPP_(dummy_PL_parser)))->var) #if defined(NEED_PL_parser) static yy_parser DPPP_(dummy_PL_parser); #elif defined(NEED_PL_parser_GLOBAL) yy_parser DPPP_(dummy_PL_parser); #else extern yy_parser DPPP_(dummy_PL_parser); #endif # endif /* PL_expect, PL_copline, PL_rsfp, PL_rsfp_filters, PL_linestr, PL_bufptr, PL_bufend, PL_lex_state, PL_lex_stuff, PL_tokenbuf depends on PL_parser */ /* Warning: PL_expect, PL_copline, PL_rsfp, PL_rsfp_filters, PL_linestr, PL_bufptr, PL_bufend, PL_lex_state, PL_lex_stuff, PL_tokenbuf * Do not use this variable unless you know exactly what you're * doint. It is internal to the perl parser and may change or even * be removed in the future. As of perl 5.9.5, you have to check * for (PL_parser != NULL) for this variable to have any effect. * An always non-NULL PL_parser dummy is provided for earlier * perl versions. * If PL_parser is NULL when you try to access this variable, a * dummy is being accessed instead and a warning is issued unless * you define DPPP_PL_parser_NO_DUMMY_WARNING. * If DPPP_PL_parser_NO_DUMMY is defined, the code trying to access * this variable will croak with a panic message. */ # define PL_expect D_PPP_my_PL_parser_var(expect) # define PL_copline D_PPP_my_PL_parser_var(copline) # define PL_rsfp D_PPP_my_PL_parser_var(rsfp) # define PL_rsfp_filters D_PPP_my_PL_parser_var(rsfp_filters) # define PL_linestr D_PPP_my_PL_parser_var(linestr) # define PL_bufptr D_PPP_my_PL_parser_var(bufptr) # define PL_bufend D_PPP_my_PL_parser_var(bufend) # define PL_lex_state D_PPP_my_PL_parser_var(lex_state) # define PL_lex_stuff D_PPP_my_PL_parser_var(lex_stuff) # define PL_tokenbuf D_PPP_my_PL_parser_var(tokenbuf) # define PL_in_my D_PPP_my_PL_parser_var(in_my) # define PL_in_my_stash D_PPP_my_PL_parser_var(in_my_stash) # define PL_error_count D_PPP_my_PL_parser_var(error_count) #else /* ensure that PL_parser != NULL and cannot be dereferenced */ # define PL_parser ((void *) 1) #endif #ifndef mPUSHs # define mPUSHs(s) PUSHs(sv_2mortal(s)) #endif #ifndef PUSHmortal # define PUSHmortal PUSHs(sv_newmortal()) #endif #ifndef mPUSHp # define mPUSHp(p,l) sv_setpvn(PUSHmortal, (p), (l)) #endif #ifndef mPUSHn # define mPUSHn(n) sv_setnv(PUSHmortal, (NV)(n)) #endif #ifndef mPUSHi # define mPUSHi(i) sv_setiv(PUSHmortal, (IV)(i)) #endif #ifndef mPUSHu # define mPUSHu(u) sv_setuv(PUSHmortal, (UV)(u)) #endif #ifndef mXPUSHs # define mXPUSHs(s) XPUSHs(sv_2mortal(s)) #endif #ifndef XPUSHmortal # define XPUSHmortal XPUSHs(sv_newmortal()) #endif #ifndef mXPUSHp # define mXPUSHp(p,l) STMT_START { EXTEND(sp,1); sv_setpvn(PUSHmortal, (p), (l)); } STMT_END #endif #ifndef mXPUSHn # define mXPUSHn(n) STMT_START { EXTEND(sp,1); sv_setnv(PUSHmortal, (NV)(n)); } STMT_END #endif #ifndef mXPUSHi # define mXPUSHi(i) STMT_START { EXTEND(sp,1); sv_setiv(PUSHmortal, (IV)(i)); } STMT_END #endif #ifndef mXPUSHu # define mXPUSHu(u) STMT_START { EXTEND(sp,1); sv_setuv(PUSHmortal, (UV)(u)); } STMT_END #endif /* Replace: 1 */ #ifndef call_sv # define call_sv perl_call_sv #endif #ifndef call_pv # define call_pv perl_call_pv #endif #ifndef call_argv # define call_argv perl_call_argv #endif #ifndef call_method # define call_method perl_call_method #endif #ifndef eval_sv # define eval_sv perl_eval_sv #endif /* Replace: 0 */ #ifndef PERL_LOADMOD_DENY # define PERL_LOADMOD_DENY 0x1 #endif #ifndef PERL_LOADMOD_NOIMPORT # define PERL_LOADMOD_NOIMPORT 0x2 #endif #ifndef PERL_LOADMOD_IMPORT_OPS # define PERL_LOADMOD_IMPORT_OPS 0x4 #endif #ifndef G_METHOD # define G_METHOD 64 # ifdef call_sv # undef call_sv # endif # if (PERL_BCDVERSION < 0x5006000) # define call_sv(sv, flags) ((flags) & G_METHOD ? perl_call_method((char *) SvPV_nolen_const(sv), \ (flags) & ~G_METHOD) : perl_call_sv(sv, flags)) # else # define call_sv(sv, flags) ((flags) & G_METHOD ? Perl_call_method(aTHX_ (char *) SvPV_nolen_const(sv), \ (flags) & ~G_METHOD) : Perl_call_sv(aTHX_ sv, flags)) # endif #endif /* Replace perl_eval_pv with eval_pv */ #ifndef eval_pv #if defined(NEED_eval_pv) static SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error); static #else extern SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error); #endif #ifdef eval_pv # undef eval_pv #endif #define eval_pv(a,b) DPPP_(my_eval_pv)(aTHX_ a,b) #define Perl_eval_pv DPPP_(my_eval_pv) #if defined(NEED_eval_pv) || defined(NEED_eval_pv_GLOBAL) SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error) { dSP; SV* sv = newSVpv(p, 0); PUSHMARK(sp); eval_sv(sv, G_SCALAR); SvREFCNT_dec(sv); SPAGAIN; sv = POPs; PUTBACK; if (croak_on_error && SvTRUE(GvSV(errgv))) croak(SvPVx(GvSV(errgv), na)); return sv; } #endif #endif #ifndef vload_module #if defined(NEED_vload_module) static void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args); static #else extern void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args); #endif #ifdef vload_module # undef vload_module #endif #define vload_module(a,b,c,d) DPPP_(my_vload_module)(aTHX_ a,b,c,d) #define Perl_vload_module DPPP_(my_vload_module) #if defined(NEED_vload_module) || defined(NEED_vload_module_GLOBAL) void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args) { dTHR; dVAR; OP *veop, *imop; OP * const modname = newSVOP(OP_CONST, 0, name); /* 5.005 has a somewhat hacky force_normal that doesn't croak on SvREADONLY() if PL_compling is true. Current perls take care in ck_require() to correctly turn off SvREADONLY before calling force_normal_flags(). This seems a better fix than fudging PL_compling */ SvREADONLY_off(((SVOP*)modname)->op_sv); modname->op_private |= OPpCONST_BARE; if (ver) { veop = newSVOP(OP_CONST, 0, ver); } else veop = NULL; if (flags & PERL_LOADMOD_NOIMPORT) { imop = sawparens(newNULLLIST()); } else if (flags & PERL_LOADMOD_IMPORT_OPS) { imop = va_arg(*args, OP*); } else { SV *sv; imop = NULL; sv = va_arg(*args, SV*); while (sv) { imop = append_elem(OP_LIST, imop, newSVOP(OP_CONST, 0, sv)); sv = va_arg(*args, SV*); } } { const line_t ocopline = PL_copline; COP * const ocurcop = PL_curcop; const int oexpect = PL_expect; #if (PERL_BCDVERSION >= 0x5004000) utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0), veop, modname, imop); #elif (PERL_BCDVERSION > 0x5003000) utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(), veop, modname, imop); #else utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(), modname, imop); #endif PL_expect = oexpect; PL_copline = ocopline; PL_curcop = ocurcop; } } #endif #endif #ifndef load_module #if defined(NEED_load_module) static void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...); static #else extern void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...); #endif #ifdef load_module # undef load_module #endif #define load_module DPPP_(my_load_module) #define Perl_load_module DPPP_(my_load_module) #if defined(NEED_load_module) || defined(NEED_load_module_GLOBAL) void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...) { va_list args; va_start(args, ver); vload_module(flags, name, ver, &args); va_end(args); } #endif #endif #ifndef newRV_inc # define newRV_inc(sv) newRV(sv) /* Replace */ #endif #ifndef newRV_noinc #if defined(NEED_newRV_noinc) static SV * DPPP_(my_newRV_noinc)(SV *sv); static #else extern SV * DPPP_(my_newRV_noinc)(SV *sv); #endif #ifdef newRV_noinc # undef newRV_noinc #endif #define newRV_noinc(a) DPPP_(my_newRV_noinc)(aTHX_ a) #define Perl_newRV_noinc DPPP_(my_newRV_noinc) #if defined(NEED_newRV_noinc) || defined(NEED_newRV_noinc_GLOBAL) SV * DPPP_(my_newRV_noinc)(SV *sv) { SV *rv = (SV *)newRV(sv); SvREFCNT_dec(sv); return rv; } #endif #endif /* Hint: newCONSTSUB * Returns a CV* as of perl-5.7.1. This return value is not supported * by Devel::PPPort. */ /* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */ #if (PERL_BCDVERSION < 0x5004063) && (PERL_BCDVERSION != 0x5004005) #if defined(NEED_newCONSTSUB) static void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv); static #else extern void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv); #endif #ifdef newCONSTSUB # undef newCONSTSUB #endif #define newCONSTSUB(a,b,c) DPPP_(my_newCONSTSUB)(aTHX_ a,b,c) #define Perl_newCONSTSUB DPPP_(my_newCONSTSUB) #if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL) /* This is just a trick to avoid a dependency of newCONSTSUB on PL_parser */ /* (There's no PL_parser in perl < 5.005, so this is completely safe) */ #define D_PPP_PL_copline PL_copline void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv) { U32 oldhints = PL_hints; HV *old_cop_stash = PL_curcop->cop_stash; HV *old_curstash = PL_curstash; line_t oldline = PL_curcop->cop_line; PL_curcop->cop_line = D_PPP_PL_copline; PL_hints &= ~HINT_BLOCK_SCOPE; if (stash) PL_curstash = PL_curcop->cop_stash = stash; newSUB( #if (PERL_BCDVERSION < 0x5003022) start_subparse(), #elif (PERL_BCDVERSION == 0x5003022) start_subparse(0), #else /* 5.003_23 onwards */ start_subparse(FALSE, 0), #endif newSVOP(OP_CONST, 0, newSVpv((char *) name, 0)), newSVOP(OP_CONST, 0, &PL_sv_no), /* SvPV(&PL_sv_no) == "" -- GMB */ newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv)) ); PL_hints = oldhints; PL_curcop->cop_stash = old_cop_stash; PL_curstash = old_curstash; PL_curcop->cop_line = oldline; } #endif #endif /* * Boilerplate macros for initializing and accessing interpreter-local * data from C. All statics in extensions should be reworked to use * this, if you want to make the extension thread-safe. See ext/re/re.xs * for an example of the use of these macros. * * Code that uses these macros is responsible for the following: * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts" * 2. Declare a typedef named my_cxt_t that is a structure that contains * all the data that needs to be interpreter-local. * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t. * 4. Use the MY_CXT_INIT macro such that it is called exactly once * (typically put in the BOOT: section). * 5. Use the members of the my_cxt_t structure everywhere as * MY_CXT.member. * 6. Use the dMY_CXT macro (a declaration) in all the functions that * access MY_CXT. */ #if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \ defined(PERL_CAPI) || defined(PERL_IMPLICIT_CONTEXT) #ifndef START_MY_CXT /* This must appear in all extensions that define a my_cxt_t structure, * right after the definition (i.e. at file scope). The non-threads * case below uses it to declare the data as static. */ #define START_MY_CXT #if (PERL_BCDVERSION < 0x5004068) /* Fetches the SV that keeps the per-interpreter data. */ #define dMY_CXT_SV \ SV *my_cxt_sv = get_sv(MY_CXT_KEY, FALSE) #else /* >= perl5.004_68 */ #define dMY_CXT_SV \ SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY, \ sizeof(MY_CXT_KEY)-1, TRUE) #endif /* < perl5.004_68 */ /* This declaration should be used within all functions that use the * interpreter-local data. */ #define dMY_CXT \ dMY_CXT_SV; \ my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv)) /* Creates and zeroes the per-interpreter data. * (We allocate my_cxtp in a Perl SV so that it will be released when * the interpreter goes away.) */ #define MY_CXT_INIT \ dMY_CXT_SV; \ /* newSV() allocates one more than needed */ \ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\ Zero(my_cxtp, 1, my_cxt_t); \ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) /* This macro must be used to access members of the my_cxt_t structure. * e.g. MYCXT.some_data */ #define MY_CXT (*my_cxtp) /* Judicious use of these macros can reduce the number of times dMY_CXT * is used. Use is similar to pTHX, aTHX etc. */ #define pMY_CXT my_cxt_t *my_cxtp #define pMY_CXT_ pMY_CXT, #define _pMY_CXT ,pMY_CXT #define aMY_CXT my_cxtp #define aMY_CXT_ aMY_CXT, #define _aMY_CXT ,aMY_CXT #endif /* START_MY_CXT */ #ifndef MY_CXT_CLONE /* Clones the per-interpreter data. */ #define MY_CXT_CLONE \ dMY_CXT_SV; \ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\ Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t);\ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) #endif #else /* single interpreter */ #ifndef START_MY_CXT #define START_MY_CXT static my_cxt_t my_cxt; #define dMY_CXT_SV dNOOP #define dMY_CXT dNOOP #define MY_CXT_INIT NOOP #define MY_CXT my_cxt #define pMY_CXT void #define pMY_CXT_ #define _pMY_CXT #define aMY_CXT #define aMY_CXT_ #define _aMY_CXT #endif /* START_MY_CXT */ #ifndef MY_CXT_CLONE #define MY_CXT_CLONE NOOP #endif #endif #ifndef IVdf # if IVSIZE == LONGSIZE # define IVdf "ld" # define UVuf "lu" # define UVof "lo" # define UVxf "lx" # define UVXf "lX" # elif IVSIZE == INTSIZE # define IVdf "d" # define UVuf "u" # define UVof "o" # define UVxf "x" # define UVXf "X" # else # error "cannot define IV/UV formats" # endif #endif #ifndef NVef # if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \ defined(PERL_PRIfldbl) && (PERL_BCDVERSION != 0x5006000) /* Not very likely, but let's try anyway. */ # define NVef PERL_PRIeldbl # define NVff PERL_PRIfldbl # define NVgf PERL_PRIgldbl # else # define NVef "e" # define NVff "f" # define NVgf "g" # endif #endif #ifndef SvREFCNT_inc # ifdef PERL_USE_GCC_BRACE_GROUPS # define SvREFCNT_inc(sv) \ ({ \ SV * const _sv = (SV*)(sv); \ if (_sv) \ (SvREFCNT(_sv))++; \ _sv; \ }) # else # define SvREFCNT_inc(sv) \ ((PL_Sv=(SV*)(sv)) ? (++(SvREFCNT(PL_Sv)),PL_Sv) : NULL) # endif #endif #ifndef SvREFCNT_inc_simple # ifdef PERL_USE_GCC_BRACE_GROUPS # define SvREFCNT_inc_simple(sv) \ ({ \ if (sv) \ (SvREFCNT(sv))++; \ (SV *)(sv); \ }) # else # define SvREFCNT_inc_simple(sv) \ ((sv) ? (SvREFCNT(sv)++,(SV*)(sv)) : NULL) # endif #endif #ifndef SvREFCNT_inc_NN # ifdef PERL_USE_GCC_BRACE_GROUPS # define SvREFCNT_inc_NN(sv) \ ({ \ SV * const _sv = (SV*)(sv); \ SvREFCNT(_sv)++; \ _sv; \ }) # else # define SvREFCNT_inc_NN(sv) \ (PL_Sv=(SV*)(sv),++(SvREFCNT(PL_Sv)),PL_Sv) # endif #endif #ifndef SvREFCNT_inc_void # ifdef PERL_USE_GCC_BRACE_GROUPS # define SvREFCNT_inc_void(sv) \ ({ \ SV * const _sv = (SV*)(sv); \ if (_sv) \ (void)(SvREFCNT(_sv)++); \ }) # else # define SvREFCNT_inc_void(sv) \ (void)((PL_Sv=(SV*)(sv)) ? ++(SvREFCNT(PL_Sv)) : 0) # endif #endif #ifndef SvREFCNT_inc_simple_void # define SvREFCNT_inc_simple_void(sv) STMT_START { if (sv) SvREFCNT(sv)++; } STMT_END #endif #ifndef SvREFCNT_inc_simple_NN # define SvREFCNT_inc_simple_NN(sv) (++SvREFCNT(sv), (SV*)(sv)) #endif #ifndef SvREFCNT_inc_void_NN # define SvREFCNT_inc_void_NN(sv) (void)(++SvREFCNT((SV*)(sv))) #endif #ifndef SvREFCNT_inc_simple_void_NN # define SvREFCNT_inc_simple_void_NN(sv) (void)(++SvREFCNT((SV*)(sv))) #endif #ifndef newSV_type #if defined(NEED_newSV_type) static SV* DPPP_(my_newSV_type)(pTHX_ svtype const t); static #else extern SV* DPPP_(my_newSV_type)(pTHX_ svtype const t); #endif #ifdef newSV_type # undef newSV_type #endif #define newSV_type(a) DPPP_(my_newSV_type)(aTHX_ a) #define Perl_newSV_type DPPP_(my_newSV_type) #if defined(NEED_newSV_type) || defined(NEED_newSV_type_GLOBAL) SV* DPPP_(my_newSV_type)(pTHX_ svtype const t) { SV* const sv = newSV(0); sv_upgrade(sv, t); return sv; } #endif #endif #if (PERL_BCDVERSION < 0x5006000) # define D_PPP_CONSTPV_ARG(x) ((char *) (x)) #else # define D_PPP_CONSTPV_ARG(x) (x) #endif #ifndef newSVpvn # define newSVpvn(data,len) ((data) \ ? ((len) ? newSVpv((data), (len)) : newSVpv("", 0)) \ : newSV(0)) #endif #ifndef newSVpvn_utf8 # define newSVpvn_utf8(s, len, u) newSVpvn_flags((s), (len), (u) ? SVf_UTF8 : 0) #endif #ifndef SVf_UTF8 # define SVf_UTF8 0 #endif #ifndef newSVpvn_flags #if defined(NEED_newSVpvn_flags) static SV * DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags); static #else extern SV * DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags); #endif #ifdef newSVpvn_flags # undef newSVpvn_flags #endif #define newSVpvn_flags(a,b,c) DPPP_(my_newSVpvn_flags)(aTHX_ a,b,c) #define Perl_newSVpvn_flags DPPP_(my_newSVpvn_flags) #if defined(NEED_newSVpvn_flags) || defined(NEED_newSVpvn_flags_GLOBAL) SV * DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags) { SV *sv = newSVpvn(D_PPP_CONSTPV_ARG(s), len); SvFLAGS(sv) |= (flags & SVf_UTF8); return (flags & SVs_TEMP) ? sv_2mortal(sv) : sv; } #endif #endif /* Backwards compatibility stuff... :-( */ #if !defined(NEED_sv_2pv_flags) && defined(NEED_sv_2pv_nolen) # define NEED_sv_2pv_flags #endif #if !defined(NEED_sv_2pv_flags_GLOBAL) && defined(NEED_sv_2pv_nolen_GLOBAL) # define NEED_sv_2pv_flags_GLOBAL #endif /* Hint: sv_2pv_nolen * Use the SvPV_nolen() or SvPV_nolen_const() macros instead of sv_2pv_nolen(). */ #ifndef sv_2pv_nolen # define sv_2pv_nolen(sv) SvPV_nolen(sv) #endif #ifdef SvPVbyte /* Hint: SvPVbyte * Does not work in perl-5.6.1, ppport.h implements a version * borrowed from perl-5.7.3. */ #if (PERL_BCDVERSION < 0x5007000) #if defined(NEED_sv_2pvbyte) static char * DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp); static #else extern char * DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp); #endif #ifdef sv_2pvbyte # undef sv_2pvbyte #endif #define sv_2pvbyte(a,b) DPPP_(my_sv_2pvbyte)(aTHX_ a,b) #define Perl_sv_2pvbyte DPPP_(my_sv_2pvbyte) #if defined(NEED_sv_2pvbyte) || defined(NEED_sv_2pvbyte_GLOBAL) char * DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp) { sv_utf8_downgrade(sv,0); return SvPV(sv,*lp); } #endif /* Hint: sv_2pvbyte * Use the SvPVbyte() macro instead of sv_2pvbyte(). */ #undef SvPVbyte #define SvPVbyte(sv, lp) \ ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \ ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pvbyte(sv, &lp)) #endif #else # define SvPVbyte SvPV # define sv_2pvbyte sv_2pv #endif #ifndef sv_2pvbyte_nolen # define sv_2pvbyte_nolen(sv) sv_2pv_nolen(sv) #endif /* Hint: sv_pvn * Always use the SvPV() macro instead of sv_pvn(). */ /* Hint: sv_pvn_force * Always use the SvPV_force() macro instead of sv_pvn_force(). */ /* If these are undefined, they're not handled by the core anyway */ #ifndef SV_IMMEDIATE_UNREF # define SV_IMMEDIATE_UNREF 0 #endif #ifndef SV_GMAGIC # define SV_GMAGIC 0 #endif #ifndef SV_COW_DROP_PV # define SV_COW_DROP_PV 0 #endif #ifndef SV_UTF8_NO_ENCODING # define SV_UTF8_NO_ENCODING 0 #endif #ifndef SV_NOSTEAL # define SV_NOSTEAL 0 #endif #ifndef SV_CONST_RETURN # define SV_CONST_RETURN 0 #endif #ifndef SV_MUTABLE_RETURN # define SV_MUTABLE_RETURN 0 #endif #ifndef SV_SMAGIC # define SV_SMAGIC 0 #endif #ifndef SV_HAS_TRAILING_NUL # define SV_HAS_TRAILING_NUL 0 #endif #ifndef SV_COW_SHARED_HASH_KEYS # define SV_COW_SHARED_HASH_KEYS 0 #endif #if (PERL_BCDVERSION < 0x5007002) #if defined(NEED_sv_2pv_flags) static char * DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); static #else extern char * DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); #endif #ifdef sv_2pv_flags # undef sv_2pv_flags #endif #define sv_2pv_flags(a,b,c) DPPP_(my_sv_2pv_flags)(aTHX_ a,b,c) #define Perl_sv_2pv_flags DPPP_(my_sv_2pv_flags) #if defined(NEED_sv_2pv_flags) || defined(NEED_sv_2pv_flags_GLOBAL) char * DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags) { STRLEN n_a = (STRLEN) flags; return sv_2pv(sv, lp ? lp : &n_a); } #endif #if defined(NEED_sv_pvn_force_flags) static char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); static #else extern char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); #endif #ifdef sv_pvn_force_flags # undef sv_pvn_force_flags #endif #define sv_pvn_force_flags(a,b,c) DPPP_(my_sv_pvn_force_flags)(aTHX_ a,b,c) #define Perl_sv_pvn_force_flags DPPP_(my_sv_pvn_force_flags) #if defined(NEED_sv_pvn_force_flags) || defined(NEED_sv_pvn_force_flags_GLOBAL) char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags) { STRLEN n_a = (STRLEN) flags; return sv_pvn_force(sv, lp ? lp : &n_a); } #endif #endif #if (PERL_BCDVERSION < 0x5008008) || ( (PERL_BCDVERSION >= 0x5009000) && (PERL_BCDVERSION < 0x5009003) ) # define DPPP_SVPV_NOLEN_LP_ARG &PL_na #else # define DPPP_SVPV_NOLEN_LP_ARG 0 #endif #ifndef SvPV_const # define SvPV_const(sv, lp) SvPV_flags_const(sv, lp, SV_GMAGIC) #endif #ifndef SvPV_mutable # define SvPV_mutable(sv, lp) SvPV_flags_mutable(sv, lp, SV_GMAGIC) #endif #ifndef SvPV_flags # define SvPV_flags(sv, lp, flags) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pv_flags(sv, &lp, flags)) #endif #ifndef SvPV_flags_const # define SvPV_flags_const(sv, lp, flags) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? ((lp = SvCUR(sv)), SvPVX_const(sv)) : \ (const char*) sv_2pv_flags(sv, &lp, flags|SV_CONST_RETURN)) #endif #ifndef SvPV_flags_const_nolen # define SvPV_flags_const_nolen(sv, flags) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? SvPVX_const(sv) : \ (const char*) sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, flags|SV_CONST_RETURN)) #endif #ifndef SvPV_flags_mutable # define SvPV_flags_mutable(sv, lp, flags) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) : \ sv_2pv_flags(sv, &lp, flags|SV_MUTABLE_RETURN)) #endif #ifndef SvPV_force # define SvPV_force(sv, lp) SvPV_force_flags(sv, lp, SV_GMAGIC) #endif #ifndef SvPV_force_nolen # define SvPV_force_nolen(sv) SvPV_force_flags_nolen(sv, SV_GMAGIC) #endif #ifndef SvPV_force_mutable # define SvPV_force_mutable(sv, lp) SvPV_force_flags_mutable(sv, lp, SV_GMAGIC) #endif #ifndef SvPV_force_nomg # define SvPV_force_nomg(sv, lp) SvPV_force_flags(sv, lp, 0) #endif #ifndef SvPV_force_nomg_nolen # define SvPV_force_nomg_nolen(sv) SvPV_force_flags_nolen(sv, 0) #endif #ifndef SvPV_force_flags # define SvPV_force_flags(sv, lp, flags) \ ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_pvn_force_flags(sv, &lp, flags)) #endif #ifndef SvPV_force_flags_nolen # define SvPV_force_flags_nolen(sv, flags) \ ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ ? SvPVX(sv) : sv_pvn_force_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, flags)) #endif #ifndef SvPV_force_flags_mutable # define SvPV_force_flags_mutable(sv, lp, flags) \ ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) \ : sv_pvn_force_flags(sv, &lp, flags|SV_MUTABLE_RETURN)) #endif #ifndef SvPV_nolen # define SvPV_nolen(sv) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? SvPVX(sv) : sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, SV_GMAGIC)) #endif #ifndef SvPV_nolen_const # define SvPV_nolen_const(sv) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? SvPVX_const(sv) : sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, SV_GMAGIC|SV_CONST_RETURN)) #endif #ifndef SvPV_nomg # define SvPV_nomg(sv, lp) SvPV_flags(sv, lp, 0) #endif #ifndef SvPV_nomg_const # define SvPV_nomg_const(sv, lp) SvPV_flags_const(sv, lp, 0) #endif #ifndef SvPV_nomg_const_nolen # define SvPV_nomg_const_nolen(sv) SvPV_flags_const_nolen(sv, 0) #endif #ifndef SvPV_nomg_nolen # define SvPV_nomg_nolen(sv) ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? SvPVX(sv) : sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, 0)) #endif #ifndef SvPV_renew # define SvPV_renew(sv,n) STMT_START { SvLEN_set(sv, n); \ SvPV_set((sv), (char *) saferealloc( \ (Malloc_t)SvPVX(sv), (MEM_SIZE)((n)))); \ } STMT_END #endif #ifndef SvMAGIC_set # define SvMAGIC_set(sv, val) \ STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \ (((XPVMG*) SvANY(sv))->xmg_magic = (val)); } STMT_END #endif #if (PERL_BCDVERSION < 0x5009003) #ifndef SvPVX_const # define SvPVX_const(sv) ((const char*) (0 + SvPVX(sv))) #endif #ifndef SvPVX_mutable # define SvPVX_mutable(sv) (0 + SvPVX(sv)) #endif #ifndef SvRV_set # define SvRV_set(sv, val) \ STMT_START { assert(SvTYPE(sv) >= SVt_RV); \ (((XRV*) SvANY(sv))->xrv_rv = (val)); } STMT_END #endif #else #ifndef SvPVX_const # define SvPVX_const(sv) ((const char*)((sv)->sv_u.svu_pv)) #endif #ifndef SvPVX_mutable # define SvPVX_mutable(sv) ((sv)->sv_u.svu_pv) #endif #ifndef SvRV_set # define SvRV_set(sv, val) \ STMT_START { assert(SvTYPE(sv) >= SVt_RV); \ ((sv)->sv_u.svu_rv = (val)); } STMT_END #endif #endif #ifndef SvSTASH_set # define SvSTASH_set(sv, val) \ STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \ (((XPVMG*) SvANY(sv))->xmg_stash = (val)); } STMT_END #endif #if (PERL_BCDVERSION < 0x5004000) #ifndef SvUV_set # define SvUV_set(sv, val) \ STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \ (((XPVIV*) SvANY(sv))->xiv_iv = (IV) (val)); } STMT_END #endif #else #ifndef SvUV_set # define SvUV_set(sv, val) \ STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \ (((XPVUV*) SvANY(sv))->xuv_uv = (val)); } STMT_END #endif #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(vnewSVpvf) #if defined(NEED_vnewSVpvf) static SV * DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args); static #else extern SV * DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args); #endif #ifdef vnewSVpvf # undef vnewSVpvf #endif #define vnewSVpvf(a,b) DPPP_(my_vnewSVpvf)(aTHX_ a,b) #define Perl_vnewSVpvf DPPP_(my_vnewSVpvf) #if defined(NEED_vnewSVpvf) || defined(NEED_vnewSVpvf_GLOBAL) SV * DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args) { register SV *sv = newSV(0); sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); return sv; } #endif #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf) # define sv_vcatpvf(sv, pat, args) sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)) #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf) # define sv_vsetpvf(sv, pat, args) sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)) #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg) #if defined(NEED_sv_catpvf_mg) static void DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...); static #else extern void DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...); #endif #define Perl_sv_catpvf_mg DPPP_(my_sv_catpvf_mg) #if defined(NEED_sv_catpvf_mg) || defined(NEED_sv_catpvf_mg_GLOBAL) void DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...) { va_list args; va_start(args, pat); sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); SvSETMAGIC(sv); va_end(args); } #endif #endif #ifdef PERL_IMPLICIT_CONTEXT #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg_nocontext) #if defined(NEED_sv_catpvf_mg_nocontext) static void DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...); static #else extern void DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...); #endif #define sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext) #define Perl_sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext) #if defined(NEED_sv_catpvf_mg_nocontext) || defined(NEED_sv_catpvf_mg_nocontext_GLOBAL) void DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...) { dTHX; va_list args; va_start(args, pat); sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); SvSETMAGIC(sv); va_end(args); } #endif #endif #endif /* sv_catpvf_mg depends on sv_catpvf_mg_nocontext */ #ifndef sv_catpvf_mg # ifdef PERL_IMPLICIT_CONTEXT # define sv_catpvf_mg Perl_sv_catpvf_mg_nocontext # else # define sv_catpvf_mg Perl_sv_catpvf_mg # endif #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf_mg) # define sv_vcatpvf_mg(sv, pat, args) \ STMT_START { \ sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \ SvSETMAGIC(sv); \ } STMT_END #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg) #if defined(NEED_sv_setpvf_mg) static void DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...); static #else extern void DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...); #endif #define Perl_sv_setpvf_mg DPPP_(my_sv_setpvf_mg) #if defined(NEED_sv_setpvf_mg) || defined(NEED_sv_setpvf_mg_GLOBAL) void DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...) { va_list args; va_start(args, pat); sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); SvSETMAGIC(sv); va_end(args); } #endif #endif #ifdef PERL_IMPLICIT_CONTEXT #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg_nocontext) #if defined(NEED_sv_setpvf_mg_nocontext) static void DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...); static #else extern void DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...); #endif #define sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext) #define Perl_sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext) #if defined(NEED_sv_setpvf_mg_nocontext) || defined(NEED_sv_setpvf_mg_nocontext_GLOBAL) void DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...) { dTHX; va_list args; va_start(args, pat); sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); SvSETMAGIC(sv); va_end(args); } #endif #endif #endif /* sv_setpvf_mg depends on sv_setpvf_mg_nocontext */ #ifndef sv_setpvf_mg # ifdef PERL_IMPLICIT_CONTEXT # define sv_setpvf_mg Perl_sv_setpvf_mg_nocontext # else # define sv_setpvf_mg Perl_sv_setpvf_mg # endif #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf_mg) # define sv_vsetpvf_mg(sv, pat, args) \ STMT_START { \ sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \ SvSETMAGIC(sv); \ } STMT_END #endif /* Hint: newSVpvn_share * The SVs created by this function only mimic the behaviour of * shared PVs without really being shared. Only use if you know * what you're doing. */ #ifndef newSVpvn_share #if defined(NEED_newSVpvn_share) static SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash); static #else extern SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash); #endif #ifdef newSVpvn_share # undef newSVpvn_share #endif #define newSVpvn_share(a,b,c) DPPP_(my_newSVpvn_share)(aTHX_ a,b,c) #define Perl_newSVpvn_share DPPP_(my_newSVpvn_share) #if defined(NEED_newSVpvn_share) || defined(NEED_newSVpvn_share_GLOBAL) SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash) { SV *sv; if (len < 0) len = -len; if (!hash) PERL_HASH(hash, (char*) src, len); sv = newSVpvn((char *) src, len); sv_upgrade(sv, SVt_PVIV); SvIVX(sv) = hash; SvREADONLY_on(sv); SvPOK_on(sv); return sv; } #endif #endif #ifndef SvSHARED_HASH # define SvSHARED_HASH(sv) (0 + SvUVX(sv)) #endif #ifndef HvNAME_get # define HvNAME_get(hv) HvNAME(hv) #endif #ifndef HvNAMELEN_get # define HvNAMELEN_get(hv) (HvNAME_get(hv) ? (I32)strlen(HvNAME_get(hv)) : 0) #endif #ifndef GvSVn # define GvSVn(gv) GvSV(gv) #endif #ifndef isGV_with_GP # define isGV_with_GP(gv) isGV(gv) #endif #ifndef gv_fetchpvn_flags # define gv_fetchpvn_flags(name, len, flags, svt) gv_fetchpv(name, flags, svt) #endif #ifndef gv_fetchsv # define gv_fetchsv(name, flags, svt) gv_fetchpv(SvPV_nolen_const(name), flags, svt) #endif #ifndef get_cvn_flags # define get_cvn_flags(name, namelen, flags) get_cv(name, flags) #endif #ifndef WARN_ALL # define WARN_ALL 0 #endif #ifndef WARN_CLOSURE # define WARN_CLOSURE 1 #endif #ifndef WARN_DEPRECATED # define WARN_DEPRECATED 2 #endif #ifndef WARN_EXITING # define WARN_EXITING 3 #endif #ifndef WARN_GLOB # define WARN_GLOB 4 #endif #ifndef WARN_IO # define WARN_IO 5 #endif #ifndef WARN_CLOSED # define WARN_CLOSED 6 #endif #ifndef WARN_EXEC # define WARN_EXEC 7 #endif #ifndef WARN_LAYER # define WARN_LAYER 8 #endif #ifndef WARN_NEWLINE # define WARN_NEWLINE 9 #endif #ifndef WARN_PIPE # define WARN_PIPE 10 #endif #ifndef WARN_UNOPENED # define WARN_UNOPENED 11 #endif #ifndef WARN_MISC # define WARN_MISC 12 #endif #ifndef WARN_NUMERIC # define WARN_NUMERIC 13 #endif #ifndef WARN_ONCE # define WARN_ONCE 14 #endif #ifndef WARN_OVERFLOW # define WARN_OVERFLOW 15 #endif #ifndef WARN_PACK # define WARN_PACK 16 #endif #ifndef WARN_PORTABLE # define WARN_PORTABLE 17 #endif #ifndef WARN_RECURSION # define WARN_RECURSION 18 #endif #ifndef WARN_REDEFINE # define WARN_REDEFINE 19 #endif #ifndef WARN_REGEXP # define WARN_REGEXP 20 #endif #ifndef WARN_SEVERE # define WARN_SEVERE 21 #endif #ifndef WARN_DEBUGGING # define WARN_DEBUGGING 22 #endif #ifndef WARN_INPLACE # define WARN_INPLACE 23 #endif #ifndef WARN_INTERNAL # define WARN_INTERNAL 24 #endif #ifndef WARN_MALLOC # define WARN_MALLOC 25 #endif #ifndef WARN_SIGNAL # define WARN_SIGNAL 26 #endif #ifndef WARN_SUBSTR # define WARN_SUBSTR 27 #endif #ifndef WARN_SYNTAX # define WARN_SYNTAX 28 #endif #ifndef WARN_AMBIGUOUS # define WARN_AMBIGUOUS 29 #endif #ifndef WARN_BAREWORD # define WARN_BAREWORD 30 #endif #ifndef WARN_DIGIT # define WARN_DIGIT 31 #endif #ifndef WARN_PARENTHESIS # define WARN_PARENTHESIS 32 #endif #ifndef WARN_PRECEDENCE # define WARN_PRECEDENCE 33 #endif #ifndef WARN_PRINTF # define WARN_PRINTF 34 #endif #ifndef WARN_PROTOTYPE # define WARN_PROTOTYPE 35 #endif #ifndef WARN_QW # define WARN_QW 36 #endif #ifndef WARN_RESERVED # define WARN_RESERVED 37 #endif #ifndef WARN_SEMICOLON # define WARN_SEMICOLON 38 #endif #ifndef WARN_TAINT # define WARN_TAINT 39 #endif #ifndef WARN_THREADS # define WARN_THREADS 40 #endif #ifndef WARN_UNINITIALIZED # define WARN_UNINITIALIZED 41 #endif #ifndef WARN_UNPACK # define WARN_UNPACK 42 #endif #ifndef WARN_UNTIE # define WARN_UNTIE 43 #endif #ifndef WARN_UTF8 # define WARN_UTF8 44 #endif #ifndef WARN_VOID # define WARN_VOID 45 #endif #ifndef WARN_ASSERTIONS # define WARN_ASSERTIONS 46 #endif #ifndef packWARN # define packWARN(a) (a) #endif #ifndef ckWARN # ifdef G_WARN_ON # define ckWARN(a) (PL_dowarn & G_WARN_ON) # else # define ckWARN(a) PL_dowarn # endif #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(warner) #if defined(NEED_warner) static void DPPP_(my_warner)(U32 err, const char *pat, ...); static #else extern void DPPP_(my_warner)(U32 err, const char *pat, ...); #endif #define Perl_warner DPPP_(my_warner) #if defined(NEED_warner) || defined(NEED_warner_GLOBAL) void DPPP_(my_warner)(U32 err, const char *pat, ...) { SV *sv; va_list args; PERL_UNUSED_ARG(err); va_start(args, pat); sv = vnewSVpvf(pat, &args); va_end(args); sv_2mortal(sv); warn("%s", SvPV_nolen(sv)); } #define warner Perl_warner #define Perl_warner_nocontext Perl_warner #endif #endif /* concatenating with "" ensures that only literal strings are accepted as argument * note that STR_WITH_LEN() can't be used as argument to macros or functions that * under some configurations might be macros */ #ifndef STR_WITH_LEN # define STR_WITH_LEN(s) (s ""), (sizeof(s)-1) #endif #ifndef newSVpvs # define newSVpvs(str) newSVpvn(str "", sizeof(str) - 1) #endif #ifndef newSVpvs_flags # define newSVpvs_flags(str, flags) newSVpvn_flags(str "", sizeof(str) - 1, flags) #endif #ifndef newSVpvs_share # define newSVpvs_share(str) newSVpvn_share(str "", sizeof(str) - 1, 0) #endif #ifndef sv_catpvs # define sv_catpvs(sv, str) sv_catpvn(sv, str "", sizeof(str) - 1) #endif #ifndef sv_setpvs # define sv_setpvs(sv, str) sv_setpvn(sv, str "", sizeof(str) - 1) #endif #ifndef hv_fetchs # define hv_fetchs(hv, key, lval) hv_fetch(hv, key "", sizeof(key) - 1, lval) #endif #ifndef hv_stores # define hv_stores(hv, key, val) hv_store(hv, key "", sizeof(key) - 1, val, 0) #endif #ifndef gv_fetchpvs # define gv_fetchpvs(name, flags, svt) gv_fetchpvn_flags(name "", sizeof(name) - 1, flags, svt) #endif #ifndef gv_stashpvs # define gv_stashpvs(name, flags) gv_stashpvn(name "", sizeof(name) - 1, flags) #endif #ifndef get_cvs # define get_cvs(name, flags) get_cvn_flags(name "", sizeof(name)-1, flags) #endif #ifndef SvGETMAGIC # define SvGETMAGIC(x) STMT_START { if (SvGMAGICAL(x)) mg_get(x); } STMT_END #endif /* Some random bits for sv_unmagicext. These should probably be pulled in for real and organized at some point */ #ifndef HEf_SVKEY # define HEf_SVKEY -2 #endif #if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) # define MUTABLE_PTR(p) ({ void *_p = (p); _p; }) #else # define MUTABLE_PTR(p) ((void *) (p)) #endif #define MUTABLE_SV(p) ((SV *)MUTABLE_PTR(p)) /* end of random bits */ #ifndef PERL_MAGIC_sv # define PERL_MAGIC_sv '\0' #endif #ifndef PERL_MAGIC_overload # define PERL_MAGIC_overload 'A' #endif #ifndef PERL_MAGIC_overload_elem # define PERL_MAGIC_overload_elem 'a' #endif #ifndef PERL_MAGIC_overload_table # define PERL_MAGIC_overload_table 'c' #endif #ifndef PERL_MAGIC_bm # define PERL_MAGIC_bm 'B' #endif #ifndef PERL_MAGIC_regdata # define PERL_MAGIC_regdata 'D' #endif #ifndef PERL_MAGIC_regdatum # define PERL_MAGIC_regdatum 'd' #endif #ifndef PERL_MAGIC_env # define PERL_MAGIC_env 'E' #endif #ifndef PERL_MAGIC_envelem # define PERL_MAGIC_envelem 'e' #endif #ifndef PERL_MAGIC_fm # define PERL_MAGIC_fm 'f' #endif #ifndef PERL_MAGIC_regex_global # define PERL_MAGIC_regex_global 'g' #endif #ifndef PERL_MAGIC_isa # define PERL_MAGIC_isa 'I' #endif #ifndef PERL_MAGIC_isaelem # define PERL_MAGIC_isaelem 'i' #endif #ifndef PERL_MAGIC_nkeys # define PERL_MAGIC_nkeys 'k' #endif #ifndef PERL_MAGIC_dbfile # define PERL_MAGIC_dbfile 'L' #endif #ifndef PERL_MAGIC_dbline # define PERL_MAGIC_dbline 'l' #endif #ifndef PERL_MAGIC_mutex # define PERL_MAGIC_mutex 'm' #endif #ifndef PERL_MAGIC_shared # define PERL_MAGIC_shared 'N' #endif #ifndef PERL_MAGIC_shared_scalar # define PERL_MAGIC_shared_scalar 'n' #endif #ifndef PERL_MAGIC_collxfrm # define PERL_MAGIC_collxfrm 'o' #endif #ifndef PERL_MAGIC_tied # define PERL_MAGIC_tied 'P' #endif #ifndef PERL_MAGIC_tiedelem # define PERL_MAGIC_tiedelem 'p' #endif #ifndef PERL_MAGIC_tiedscalar # define PERL_MAGIC_tiedscalar 'q' #endif #ifndef PERL_MAGIC_qr # define PERL_MAGIC_qr 'r' #endif #ifndef PERL_MAGIC_sig # define PERL_MAGIC_sig 'S' #endif #ifndef PERL_MAGIC_sigelem # define PERL_MAGIC_sigelem 's' #endif #ifndef PERL_MAGIC_taint # define PERL_MAGIC_taint 't' #endif #ifndef PERL_MAGIC_uvar # define PERL_MAGIC_uvar 'U' #endif #ifndef PERL_MAGIC_uvar_elem # define PERL_MAGIC_uvar_elem 'u' #endif #ifndef PERL_MAGIC_vstring # define PERL_MAGIC_vstring 'V' #endif #ifndef PERL_MAGIC_vec # define PERL_MAGIC_vec 'v' #endif #ifndef PERL_MAGIC_utf8 # define PERL_MAGIC_utf8 'w' #endif #ifndef PERL_MAGIC_substr # define PERL_MAGIC_substr 'x' #endif #ifndef PERL_MAGIC_defelem # define PERL_MAGIC_defelem 'y' #endif #ifndef PERL_MAGIC_glob # define PERL_MAGIC_glob '*' #endif #ifndef PERL_MAGIC_arylen # define PERL_MAGIC_arylen '#' #endif #ifndef PERL_MAGIC_pos # define PERL_MAGIC_pos '.' #endif #ifndef PERL_MAGIC_backref # define PERL_MAGIC_backref '<' #endif #ifndef PERL_MAGIC_ext # define PERL_MAGIC_ext '~' #endif /* That's the best we can do... */ #ifndef sv_catpvn_nomg # define sv_catpvn_nomg sv_catpvn #endif #ifndef sv_catsv_nomg # define sv_catsv_nomg sv_catsv #endif #ifndef sv_setsv_nomg # define sv_setsv_nomg sv_setsv #endif #ifndef sv_pvn_nomg # define sv_pvn_nomg sv_pvn #endif #ifndef SvIV_nomg # define SvIV_nomg SvIV #endif #ifndef SvUV_nomg # define SvUV_nomg SvUV #endif #ifndef sv_catpv_mg # define sv_catpv_mg(sv, ptr) \ STMT_START { \ SV *TeMpSv = sv; \ sv_catpv(TeMpSv,ptr); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_catpvn_mg # define sv_catpvn_mg(sv, ptr, len) \ STMT_START { \ SV *TeMpSv = sv; \ sv_catpvn(TeMpSv,ptr,len); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_catsv_mg # define sv_catsv_mg(dsv, ssv) \ STMT_START { \ SV *TeMpSv = dsv; \ sv_catsv(TeMpSv,ssv); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setiv_mg # define sv_setiv_mg(sv, i) \ STMT_START { \ SV *TeMpSv = sv; \ sv_setiv(TeMpSv,i); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setnv_mg # define sv_setnv_mg(sv, num) \ STMT_START { \ SV *TeMpSv = sv; \ sv_setnv(TeMpSv,num); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setpv_mg # define sv_setpv_mg(sv, ptr) \ STMT_START { \ SV *TeMpSv = sv; \ sv_setpv(TeMpSv,ptr); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setpvn_mg # define sv_setpvn_mg(sv, ptr, len) \ STMT_START { \ SV *TeMpSv = sv; \ sv_setpvn(TeMpSv,ptr,len); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setsv_mg # define sv_setsv_mg(dsv, ssv) \ STMT_START { \ SV *TeMpSv = dsv; \ sv_setsv(TeMpSv,ssv); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setuv_mg # define sv_setuv_mg(sv, i) \ STMT_START { \ SV *TeMpSv = sv; \ sv_setuv(TeMpSv,i); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_usepvn_mg # define sv_usepvn_mg(sv, ptr, len) \ STMT_START { \ SV *TeMpSv = sv; \ sv_usepvn(TeMpSv,ptr,len); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef SvVSTRING_mg # define SvVSTRING_mg(sv) (SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_vstring) : NULL) #endif /* Hint: sv_magic_portable * This is a compatibility function that is only available with * Devel::PPPort. It is NOT in the perl core. * Its purpose is to mimic the 5.8.0 behaviour of sv_magic() when * it is being passed a name pointer with namlen == 0. In that * case, perl 5.8.0 and later store the pointer, not a copy of it. * The compatibility can be provided back to perl 5.004. With * earlier versions, the code will not compile. */ #if (PERL_BCDVERSION < 0x5004000) /* code that uses sv_magic_portable will not compile */ #elif (PERL_BCDVERSION < 0x5008000) # define sv_magic_portable(sv, obj, how, name, namlen) \ STMT_START { \ SV *SvMp_sv = (sv); \ char *SvMp_name = (char *) (name); \ I32 SvMp_namlen = (namlen); \ if (SvMp_name && SvMp_namlen == 0) \ { \ MAGIC *mg; \ sv_magic(SvMp_sv, obj, how, 0, 0); \ mg = SvMAGIC(SvMp_sv); \ mg->mg_len = -42; /* XXX: this is the tricky part */ \ mg->mg_ptr = SvMp_name; \ } \ else \ { \ sv_magic(SvMp_sv, obj, how, SvMp_name, SvMp_namlen); \ } \ } STMT_END #else # define sv_magic_portable(a, b, c, d, e) sv_magic(a, b, c, d, e) #endif #if !defined(mg_findext) #if defined(NEED_mg_findext) static MAGIC * DPPP_(my_mg_findext)(SV * sv, int type, const MGVTBL *vtbl); static #else extern MAGIC * DPPP_(my_mg_findext)(SV * sv, int type, const MGVTBL *vtbl); #endif #define mg_findext DPPP_(my_mg_findext) #define Perl_mg_findext DPPP_(my_mg_findext) #if defined(NEED_mg_findext) || defined(NEED_mg_findext_GLOBAL) MAGIC * DPPP_(my_mg_findext)(SV * sv, int type, const MGVTBL *vtbl) { if (sv) { MAGIC *mg; #ifdef AvPAD_NAMELIST assert(!(SvTYPE(sv) == SVt_PVAV && AvPAD_NAMELIST(sv))); #endif for (mg = SvMAGIC (sv); mg; mg = mg->mg_moremagic) { if (mg->mg_type == type && mg->mg_virtual == vtbl) return mg; } } return NULL; } #endif #endif #if !defined(sv_unmagicext) #if defined(NEED_sv_unmagicext) static int DPPP_(my_sv_unmagicext)(pTHX_ SV * const sv, const int type, MGVTBL * vtbl); static #else extern int DPPP_(my_sv_unmagicext)(pTHX_ SV * const sv, const int type, MGVTBL * vtbl); #endif #ifdef sv_unmagicext # undef sv_unmagicext #endif #define sv_unmagicext(a,b,c) DPPP_(my_sv_unmagicext)(aTHX_ a,b,c) #define Perl_sv_unmagicext DPPP_(my_sv_unmagicext) #if defined(NEED_sv_unmagicext) || defined(NEED_sv_unmagicext_GLOBAL) int DPPP_(my_sv_unmagicext)(pTHX_ SV *const sv, const int type, MGVTBL *vtbl) { MAGIC* mg; MAGIC** mgp; if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv)) return 0; mgp = &(SvMAGIC(sv)); for (mg = *mgp; mg; mg = *mgp) { const MGVTBL* const virt = mg->mg_virtual; if (mg->mg_type == type && virt == vtbl) { *mgp = mg->mg_moremagic; if (virt && virt->svt_free) virt->svt_free(aTHX_ sv, mg); if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) { if (mg->mg_len > 0) Safefree(mg->mg_ptr); else if (mg->mg_len == HEf_SVKEY) /* Questionable on older perls... */ SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr)); else if (mg->mg_type == PERL_MAGIC_utf8) Safefree(mg->mg_ptr); } if (mg->mg_flags & MGf_REFCOUNTED) SvREFCNT_dec(mg->mg_obj); Safefree(mg); } else mgp = &mg->mg_moremagic; } if (SvMAGIC(sv)) { if (SvMAGICAL(sv)) /* if we're under save_magic, wait for restore_magic; */ mg_magical(sv); /* else fix the flags now */ } else { SvMAGICAL_off(sv); SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT; } return 0; } #endif #endif #ifdef USE_ITHREADS #ifndef CopFILE # define CopFILE(c) ((c)->cop_file) #endif #ifndef CopFILEGV # define CopFILEGV(c) (CopFILE(c) ? gv_fetchfile(CopFILE(c)) : Nullgv) #endif #ifndef CopFILE_set # define CopFILE_set(c,pv) ((c)->cop_file = savepv(pv)) #endif #ifndef CopFILESV # define CopFILESV(c) (CopFILE(c) ? GvSV(gv_fetchfile(CopFILE(c))) : Nullsv) #endif #ifndef CopFILEAV # define CopFILEAV(c) (CopFILE(c) ? GvAV(gv_fetchfile(CopFILE(c))) : Nullav) #endif #ifndef CopSTASHPV # define CopSTASHPV(c) ((c)->cop_stashpv) #endif #ifndef CopSTASHPV_set # define CopSTASHPV_set(c,pv) ((c)->cop_stashpv = ((pv) ? savepv(pv) : Nullch)) #endif #ifndef CopSTASH # define CopSTASH(c) (CopSTASHPV(c) ? gv_stashpv(CopSTASHPV(c),GV_ADD) : Nullhv) #endif #ifndef CopSTASH_set # define CopSTASH_set(c,hv) CopSTASHPV_set(c, (hv) ? HvNAME(hv) : Nullch) #endif #ifndef CopSTASH_eq # define CopSTASH_eq(c,hv) ((hv) && (CopSTASHPV(c) == HvNAME(hv) \ || (CopSTASHPV(c) && HvNAME(hv) \ && strEQ(CopSTASHPV(c), HvNAME(hv))))) #endif #else #ifndef CopFILEGV # define CopFILEGV(c) ((c)->cop_filegv) #endif #ifndef CopFILEGV_set # define CopFILEGV_set(c,gv) ((c)->cop_filegv = (GV*)SvREFCNT_inc(gv)) #endif #ifndef CopFILE_set # define CopFILE_set(c,pv) CopFILEGV_set((c), gv_fetchfile(pv)) #endif #ifndef CopFILESV # define CopFILESV(c) (CopFILEGV(c) ? GvSV(CopFILEGV(c)) : Nullsv) #endif #ifndef CopFILEAV # define CopFILEAV(c) (CopFILEGV(c) ? GvAV(CopFILEGV(c)) : Nullav) #endif #ifndef CopFILE # define CopFILE(c) (CopFILESV(c) ? SvPVX(CopFILESV(c)) : Nullch) #endif #ifndef CopSTASH # define CopSTASH(c) ((c)->cop_stash) #endif #ifndef CopSTASH_set # define CopSTASH_set(c,hv) ((c)->cop_stash = (hv)) #endif #ifndef CopSTASHPV # define CopSTASHPV(c) (CopSTASH(c) ? HvNAME(CopSTASH(c)) : Nullch) #endif #ifndef CopSTASHPV_set # define CopSTASHPV_set(c,pv) CopSTASH_set((c), gv_stashpv(pv,GV_ADD)) #endif #ifndef CopSTASH_eq # define CopSTASH_eq(c,hv) (CopSTASH(c) == (hv)) #endif #endif /* USE_ITHREADS */ #if (PERL_BCDVERSION >= 0x5006000) #ifndef caller_cx # if defined(NEED_caller_cx) || defined(NEED_caller_cx_GLOBAL) static I32 DPPP_dopoptosub_at(const PERL_CONTEXT *cxstk, I32 startingblock) { I32 i; for (i = startingblock; i >= 0; i--) { register const PERL_CONTEXT * const cx = &cxstk[i]; switch (CxTYPE(cx)) { default: continue; case CXt_EVAL: case CXt_SUB: case CXt_FORMAT: return i; } } return i; } # endif # if defined(NEED_caller_cx) static const PERL_CONTEXT * DPPP_(my_caller_cx)(pTHX_ I32 count, const PERL_CONTEXT **dbcxp); static #else extern const PERL_CONTEXT * DPPP_(my_caller_cx)(pTHX_ I32 count, const PERL_CONTEXT **dbcxp); #endif #ifdef caller_cx # undef caller_cx #endif #define caller_cx(a,b) DPPP_(my_caller_cx)(aTHX_ a,b) #define Perl_caller_cx DPPP_(my_caller_cx) #if defined(NEED_caller_cx) || defined(NEED_caller_cx_GLOBAL) const PERL_CONTEXT * DPPP_(my_caller_cx)(pTHX_ I32 count, const PERL_CONTEXT **dbcxp) { register I32 cxix = DPPP_dopoptosub_at(cxstack, cxstack_ix); register const PERL_CONTEXT *cx; register const PERL_CONTEXT *ccstack = cxstack; const PERL_SI *top_si = PL_curstackinfo; for (;;) { /* we may be in a higher stacklevel, so dig down deeper */ while (cxix < 0 && top_si->si_type != PERLSI_MAIN) { top_si = top_si->si_prev; ccstack = top_si->si_cxstack; cxix = DPPP_dopoptosub_at(ccstack, top_si->si_cxix); } if (cxix < 0) return NULL; /* caller() should not report the automatic calls to &DB::sub */ if (PL_DBsub && GvCV(PL_DBsub) && cxix >= 0 && ccstack[cxix].blk_sub.cv == GvCV(PL_DBsub)) count++; if (!count--) break; cxix = DPPP_dopoptosub_at(ccstack, cxix - 1); } cx = &ccstack[cxix]; if (dbcxp) *dbcxp = cx; if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT) { const I32 dbcxix = DPPP_dopoptosub_at(ccstack, cxix - 1); /* We expect that ccstack[dbcxix] is CXt_SUB, anyway, the field below is defined for any cx. */ /* caller() should not report the automatic calls to &DB::sub */ if (PL_DBsub && GvCV(PL_DBsub) && dbcxix >= 0 && ccstack[dbcxix].blk_sub.cv == GvCV(PL_DBsub)) cx = &ccstack[dbcxix]; } return cx; } # endif #endif /* caller_cx */ #endif /* 5.6.0 */ #ifndef IN_PERL_COMPILETIME # define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling) #endif #ifndef IN_LOCALE_RUNTIME # define IN_LOCALE_RUNTIME (PL_curcop->op_private & HINT_LOCALE) #endif #ifndef IN_LOCALE_COMPILETIME # define IN_LOCALE_COMPILETIME (PL_hints & HINT_LOCALE) #endif #ifndef IN_LOCALE # define IN_LOCALE (IN_PERL_COMPILETIME ? IN_LOCALE_COMPILETIME : IN_LOCALE_RUNTIME) #endif #ifndef IS_NUMBER_IN_UV # define IS_NUMBER_IN_UV 0x01 #endif #ifndef IS_NUMBER_GREATER_THAN_UV_MAX # define IS_NUMBER_GREATER_THAN_UV_MAX 0x02 #endif #ifndef IS_NUMBER_NOT_INT # define IS_NUMBER_NOT_INT 0x04 #endif #ifndef IS_NUMBER_NEG # define IS_NUMBER_NEG 0x08 #endif #ifndef IS_NUMBER_INFINITY # define IS_NUMBER_INFINITY 0x10 #endif #ifndef IS_NUMBER_NAN # define IS_NUMBER_NAN 0x20 #endif #ifndef GROK_NUMERIC_RADIX # define GROK_NUMERIC_RADIX(sp, send) grok_numeric_radix(sp, send) #endif #ifndef PERL_SCAN_GREATER_THAN_UV_MAX # define PERL_SCAN_GREATER_THAN_UV_MAX 0x02 #endif #ifndef PERL_SCAN_SILENT_ILLDIGIT # define PERL_SCAN_SILENT_ILLDIGIT 0x04 #endif #ifndef PERL_SCAN_ALLOW_UNDERSCORES # define PERL_SCAN_ALLOW_UNDERSCORES 0x01 #endif #ifndef PERL_SCAN_DISALLOW_PREFIX # define PERL_SCAN_DISALLOW_PREFIX 0x02 #endif #ifndef grok_numeric_radix #if defined(NEED_grok_numeric_radix) static bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send); static #else extern bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send); #endif #ifdef grok_numeric_radix # undef grok_numeric_radix #endif #define grok_numeric_radix(a,b) DPPP_(my_grok_numeric_radix)(aTHX_ a,b) #define Perl_grok_numeric_radix DPPP_(my_grok_numeric_radix) #if defined(NEED_grok_numeric_radix) || defined(NEED_grok_numeric_radix_GLOBAL) bool DPPP_(my_grok_numeric_radix)(pTHX_ const char **sp, const char *send) { #ifdef USE_LOCALE_NUMERIC #ifdef PL_numeric_radix_sv if (PL_numeric_radix_sv && IN_LOCALE) { STRLEN len; char* radix = SvPV(PL_numeric_radix_sv, len); if (*sp + len <= send && memEQ(*sp, radix, len)) { *sp += len; return TRUE; } } #else /* older perls don't have PL_numeric_radix_sv so the radix * must manually be requested from locale.h */ #include dTHR; /* needed for older threaded perls */ struct lconv *lc = localeconv(); char *radix = lc->decimal_point; if (radix && IN_LOCALE) { STRLEN len = strlen(radix); if (*sp + len <= send && memEQ(*sp, radix, len)) { *sp += len; return TRUE; } } #endif #endif /* USE_LOCALE_NUMERIC */ /* always try "." if numeric radix didn't match because * we may have data from different locales mixed */ if (*sp < send && **sp == '.') { ++*sp; return TRUE; } return FALSE; } #endif #endif #ifndef grok_number #if defined(NEED_grok_number) static int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep); static #else extern int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep); #endif #ifdef grok_number # undef grok_number #endif #define grok_number(a,b,c) DPPP_(my_grok_number)(aTHX_ a,b,c) #define Perl_grok_number DPPP_(my_grok_number) #if defined(NEED_grok_number) || defined(NEED_grok_number_GLOBAL) int DPPP_(my_grok_number)(pTHX_ const char *pv, STRLEN len, UV *valuep) { const char *s = pv; const char *send = pv + len; const UV max_div_10 = UV_MAX / 10; const char max_mod_10 = UV_MAX % 10; int numtype = 0; int sawinf = 0; int sawnan = 0; while (s < send && isSPACE(*s)) s++; if (s == send) { return 0; } else if (*s == '-') { s++; numtype = IS_NUMBER_NEG; } else if (*s == '+') s++; if (s == send) return 0; /* next must be digit or the radix separator or beginning of infinity */ if (isDIGIT(*s)) { /* UVs are at least 32 bits, so the first 9 decimal digits cannot overflow. */ UV value = *s - '0'; /* This construction seems to be more optimiser friendly. (without it gcc does the isDIGIT test and the *s - '0' separately) With it gcc on arm is managing 6 instructions (6 cycles) per digit. In theory the optimiser could deduce how far to unroll the loop before checking for overflow. */ if (++s < send) { int digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { /* Now got 9 digits, so need to check each time for overflow. */ digit = *s - '0'; while (digit >= 0 && digit <= 9 && (value < max_div_10 || (value == max_div_10 && digit <= max_mod_10))) { value = value * 10 + digit; if (++s < send) digit = *s - '0'; else break; } if (digit >= 0 && digit <= 9 && (s < send)) { /* value overflowed. skip the remaining digits, don't worry about setting *valuep. */ do { s++; } while (s < send && isDIGIT(*s)); numtype |= IS_NUMBER_GREATER_THAN_UV_MAX; goto skip_value; } } } } } } } } } } } } } } } } } } numtype |= IS_NUMBER_IN_UV; if (valuep) *valuep = value; skip_value: if (GROK_NUMERIC_RADIX(&s, send)) { numtype |= IS_NUMBER_NOT_INT; while (s < send && isDIGIT(*s)) /* optional digits after the radix */ s++; } } else if (GROK_NUMERIC_RADIX(&s, send)) { numtype |= IS_NUMBER_NOT_INT | IS_NUMBER_IN_UV; /* valuep assigned below */ /* no digits before the radix means we need digits after it */ if (s < send && isDIGIT(*s)) { do { s++; } while (s < send && isDIGIT(*s)); if (valuep) { /* integer approximation is valid - it's 0. */ *valuep = 0; } } else return 0; } else if (*s == 'I' || *s == 'i') { s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; s++; if (s == send || (*s != 'F' && *s != 'f')) return 0; s++; if (s < send && (*s == 'I' || *s == 'i')) { s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; s++; if (s == send || (*s != 'I' && *s != 'i')) return 0; s++; if (s == send || (*s != 'T' && *s != 't')) return 0; s++; if (s == send || (*s != 'Y' && *s != 'y')) return 0; s++; } sawinf = 1; } else if (*s == 'N' || *s == 'n') { /* XXX TODO: There are signaling NaNs and quiet NaNs. */ s++; if (s == send || (*s != 'A' && *s != 'a')) return 0; s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; s++; sawnan = 1; } else return 0; if (sawinf) { numtype &= IS_NUMBER_NEG; /* Keep track of sign */ numtype |= IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT; } else if (sawnan) { numtype &= IS_NUMBER_NEG; /* Keep track of sign */ numtype |= IS_NUMBER_NAN | IS_NUMBER_NOT_INT; } else if (s < send) { /* we can have an optional exponent part */ if (*s == 'e' || *s == 'E') { /* The only flag we keep is sign. Blow away any "it's UV" */ numtype &= IS_NUMBER_NEG; numtype |= IS_NUMBER_NOT_INT; s++; if (s < send && (*s == '-' || *s == '+')) s++; if (s < send && isDIGIT(*s)) { do { s++; } while (s < send && isDIGIT(*s)); } else return 0; } } while (s < send && isSPACE(*s)) s++; if (s >= send) return numtype; if (len == 10 && memEQ(pv, "0 but true", 10)) { if (valuep) *valuep = 0; return IS_NUMBER_IN_UV; } return 0; } #endif #endif /* * The grok_* routines have been modified to use warn() instead of * Perl_warner(). Also, 'hexdigit' was the former name of PL_hexdigit, * which is why the stack variable has been renamed to 'xdigit'. */ #ifndef grok_bin #if defined(NEED_grok_bin) static UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); static #else extern UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); #endif #ifdef grok_bin # undef grok_bin #endif #define grok_bin(a,b,c,d) DPPP_(my_grok_bin)(aTHX_ a,b,c,d) #define Perl_grok_bin DPPP_(my_grok_bin) #if defined(NEED_grok_bin) || defined(NEED_grok_bin_GLOBAL) UV DPPP_(my_grok_bin)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) { const char *s = start; STRLEN len = *len_p; UV value = 0; NV value_nv = 0; const UV max_div_2 = UV_MAX / 2; bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; bool overflowed = FALSE; if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) { /* strip off leading b or 0b. for compatibility silently suffer "b" and "0b" as valid binary numbers. */ if (len >= 1) { if (s[0] == 'b') { s++; len--; } else if (len >= 2 && s[0] == '0' && s[1] == 'b') { s+=2; len-=2; } } } for (; len-- && *s; s++) { char bit = *s; if (bit == '0' || bit == '1') { /* Write it in this wonky order with a goto to attempt to get the compiler to make the common case integer-only loop pretty tight. With gcc seems to be much straighter code than old scan_bin. */ redo: if (!overflowed) { if (value <= max_div_2) { value = (value << 1) | (bit - '0'); continue; } /* Bah. We're just overflowed. */ warn("Integer overflow in binary number"); overflowed = TRUE; value_nv = (NV) value; } value_nv *= 2.0; /* If an NV has not enough bits in its mantissa to * represent a UV this summing of small low-order numbers * is a waste of time (because the NV cannot preserve * the low-order bits anyway): we could just remember when * did we overflow and in the end just multiply value_nv by the * right amount. */ value_nv += (NV)(bit - '0'); continue; } if (bit == '_' && len && allow_underscores && (bit = s[1]) && (bit == '0' || bit == '1')) { --len; ++s; goto redo; } if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) warn("Illegal binary digit '%c' ignored", *s); break; } if ( ( overflowed && value_nv > 4294967295.0) #if UVSIZE > 4 || (!overflowed && value > 0xffffffff ) #endif ) { warn("Binary number > 0b11111111111111111111111111111111 non-portable"); } *len_p = s - start; if (!overflowed) { *flags = 0; return value; } *flags = PERL_SCAN_GREATER_THAN_UV_MAX; if (result) *result = value_nv; return UV_MAX; } #endif #endif #ifndef grok_hex #if defined(NEED_grok_hex) static UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); static #else extern UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); #endif #ifdef grok_hex # undef grok_hex #endif #define grok_hex(a,b,c,d) DPPP_(my_grok_hex)(aTHX_ a,b,c,d) #define Perl_grok_hex DPPP_(my_grok_hex) #if defined(NEED_grok_hex) || defined(NEED_grok_hex_GLOBAL) UV DPPP_(my_grok_hex)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) { const char *s = start; STRLEN len = *len_p; UV value = 0; NV value_nv = 0; const UV max_div_16 = UV_MAX / 16; bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; bool overflowed = FALSE; const char *xdigit; if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) { /* strip off leading x or 0x. for compatibility silently suffer "x" and "0x" as valid hex numbers. */ if (len >= 1) { if (s[0] == 'x') { s++; len--; } else if (len >= 2 && s[0] == '0' && s[1] == 'x') { s+=2; len-=2; } } } for (; len-- && *s; s++) { xdigit = strchr((char *) PL_hexdigit, *s); if (xdigit) { /* Write it in this wonky order with a goto to attempt to get the compiler to make the common case integer-only loop pretty tight. With gcc seems to be much straighter code than old scan_hex. */ redo: if (!overflowed) { if (value <= max_div_16) { value = (value << 4) | ((xdigit - PL_hexdigit) & 15); continue; } warn("Integer overflow in hexadecimal number"); overflowed = TRUE; value_nv = (NV) value; } value_nv *= 16.0; /* If an NV has not enough bits in its mantissa to * represent a UV this summing of small low-order numbers * is a waste of time (because the NV cannot preserve * the low-order bits anyway): we could just remember when * did we overflow and in the end just multiply value_nv by the * right amount of 16-tuples. */ value_nv += (NV)((xdigit - PL_hexdigit) & 15); continue; } if (*s == '_' && len && allow_underscores && s[1] && (xdigit = strchr((char *) PL_hexdigit, s[1]))) { --len; ++s; goto redo; } if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) warn("Illegal hexadecimal digit '%c' ignored", *s); break; } if ( ( overflowed && value_nv > 4294967295.0) #if UVSIZE > 4 || (!overflowed && value > 0xffffffff ) #endif ) { warn("Hexadecimal number > 0xffffffff non-portable"); } *len_p = s - start; if (!overflowed) { *flags = 0; return value; } *flags = PERL_SCAN_GREATER_THAN_UV_MAX; if (result) *result = value_nv; return UV_MAX; } #endif #endif #ifndef grok_oct #if defined(NEED_grok_oct) static UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); static #else extern UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); #endif #ifdef grok_oct # undef grok_oct #endif #define grok_oct(a,b,c,d) DPPP_(my_grok_oct)(aTHX_ a,b,c,d) #define Perl_grok_oct DPPP_(my_grok_oct) #if defined(NEED_grok_oct) || defined(NEED_grok_oct_GLOBAL) UV DPPP_(my_grok_oct)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) { const char *s = start; STRLEN len = *len_p; UV value = 0; NV value_nv = 0; const UV max_div_8 = UV_MAX / 8; bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; bool overflowed = FALSE; for (; len-- && *s; s++) { /* gcc 2.95 optimiser not smart enough to figure that this subtraction out front allows slicker code. */ int digit = *s - '0'; if (digit >= 0 && digit <= 7) { /* Write it in this wonky order with a goto to attempt to get the compiler to make the common case integer-only loop pretty tight. */ redo: if (!overflowed) { if (value <= max_div_8) { value = (value << 3) | digit; continue; } /* Bah. We're just overflowed. */ warn("Integer overflow in octal number"); overflowed = TRUE; value_nv = (NV) value; } value_nv *= 8.0; /* If an NV has not enough bits in its mantissa to * represent a UV this summing of small low-order numbers * is a waste of time (because the NV cannot preserve * the low-order bits anyway): we could just remember when * did we overflow and in the end just multiply value_nv by the * right amount of 8-tuples. */ value_nv += (NV)digit; continue; } if (digit == ('_' - '0') && len && allow_underscores && (digit = s[1] - '0') && (digit >= 0 && digit <= 7)) { --len; ++s; goto redo; } /* Allow \octal to work the DWIM way (that is, stop scanning * as soon as non-octal characters are seen, complain only iff * someone seems to want to use the digits eight and nine). */ if (digit == 8 || digit == 9) { if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) warn("Illegal octal digit '%c' ignored", *s); } break; } if ( ( overflowed && value_nv > 4294967295.0) #if UVSIZE > 4 || (!overflowed && value > 0xffffffff ) #endif ) { warn("Octal number > 037777777777 non-portable"); } *len_p = s - start; if (!overflowed) { *flags = 0; return value; } *flags = PERL_SCAN_GREATER_THAN_UV_MAX; if (result) *result = value_nv; return UV_MAX; } #endif #endif #if !defined(my_snprintf) #if defined(NEED_my_snprintf) static int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...); static #else extern int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...); #endif #define my_snprintf DPPP_(my_my_snprintf) #define Perl_my_snprintf DPPP_(my_my_snprintf) #if defined(NEED_my_snprintf) || defined(NEED_my_snprintf_GLOBAL) int DPPP_(my_my_snprintf)(char *buffer, const Size_t len, const char *format, ...) { dTHX; int retval; va_list ap; va_start(ap, format); #ifdef HAS_VSNPRINTF retval = vsnprintf(buffer, len, format, ap); #else retval = vsprintf(buffer, format, ap); #endif va_end(ap); if (retval < 0 || (len > 0 && (Size_t)retval >= len)) Perl_croak(aTHX_ "panic: my_snprintf buffer overflow"); return retval; } #endif #endif #if !defined(my_sprintf) #if defined(NEED_my_sprintf) static int DPPP_(my_my_sprintf)(char * buffer, const char * pat, ...); static #else extern int DPPP_(my_my_sprintf)(char * buffer, const char * pat, ...); #endif #define my_sprintf DPPP_(my_my_sprintf) #define Perl_my_sprintf DPPP_(my_my_sprintf) #if defined(NEED_my_sprintf) || defined(NEED_my_sprintf_GLOBAL) int DPPP_(my_my_sprintf)(char *buffer, const char* pat, ...) { va_list args; va_start(args, pat); vsprintf(buffer, pat, args); va_end(args); return strlen(buffer); } #endif #endif #ifdef NO_XSLOCKS # ifdef dJMPENV # define dXCPT dJMPENV; int rEtV = 0 # define XCPT_TRY_START JMPENV_PUSH(rEtV); if (rEtV == 0) # define XCPT_TRY_END JMPENV_POP; # define XCPT_CATCH if (rEtV != 0) # define XCPT_RETHROW JMPENV_JUMP(rEtV) # else # define dXCPT Sigjmp_buf oldTOP; int rEtV = 0 # define XCPT_TRY_START Copy(top_env, oldTOP, 1, Sigjmp_buf); rEtV = Sigsetjmp(top_env, 1); if (rEtV == 0) # define XCPT_TRY_END Copy(oldTOP, top_env, 1, Sigjmp_buf); # define XCPT_CATCH if (rEtV != 0) # define XCPT_RETHROW Siglongjmp(top_env, rEtV) # endif #endif #if !defined(my_strlcat) #if defined(NEED_my_strlcat) static Size_t DPPP_(my_my_strlcat)(char * dst, const char * src, Size_t size); static #else extern Size_t DPPP_(my_my_strlcat)(char * dst, const char * src, Size_t size); #endif #define my_strlcat DPPP_(my_my_strlcat) #define Perl_my_strlcat DPPP_(my_my_strlcat) #if defined(NEED_my_strlcat) || defined(NEED_my_strlcat_GLOBAL) Size_t DPPP_(my_my_strlcat)(char *dst, const char *src, Size_t size) { Size_t used, length, copy; used = strlen(dst); length = strlen(src); if (size > 0 && used < size - 1) { copy = (length >= size - used) ? size - used - 1 : length; memcpy(dst + used, src, copy); dst[used + copy] = '\0'; } return used + length; } #endif #endif #if !defined(my_strlcpy) #if defined(NEED_my_strlcpy) static Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size); static #else extern Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size); #endif #define my_strlcpy DPPP_(my_my_strlcpy) #define Perl_my_strlcpy DPPP_(my_my_strlcpy) #if defined(NEED_my_strlcpy) || defined(NEED_my_strlcpy_GLOBAL) Size_t DPPP_(my_my_strlcpy)(char *dst, const char *src, Size_t size) { Size_t length, copy; length = strlen(src); if (size > 0) { copy = (length >= size) ? size - 1 : length; memcpy(dst, src, copy); dst[copy] = '\0'; } return length; } #endif #endif #ifndef PERL_PV_ESCAPE_QUOTE # define PERL_PV_ESCAPE_QUOTE 0x0001 #endif #ifndef PERL_PV_PRETTY_QUOTE # define PERL_PV_PRETTY_QUOTE PERL_PV_ESCAPE_QUOTE #endif #ifndef PERL_PV_PRETTY_ELLIPSES # define PERL_PV_PRETTY_ELLIPSES 0x0002 #endif #ifndef PERL_PV_PRETTY_LTGT # define PERL_PV_PRETTY_LTGT 0x0004 #endif #ifndef PERL_PV_ESCAPE_FIRSTCHAR # define PERL_PV_ESCAPE_FIRSTCHAR 0x0008 #endif #ifndef PERL_PV_ESCAPE_UNI # define PERL_PV_ESCAPE_UNI 0x0100 #endif #ifndef PERL_PV_ESCAPE_UNI_DETECT # define PERL_PV_ESCAPE_UNI_DETECT 0x0200 #endif #ifndef PERL_PV_ESCAPE_ALL # define PERL_PV_ESCAPE_ALL 0x1000 #endif #ifndef PERL_PV_ESCAPE_NOBACKSLASH # define PERL_PV_ESCAPE_NOBACKSLASH 0x2000 #endif #ifndef PERL_PV_ESCAPE_NOCLEAR # define PERL_PV_ESCAPE_NOCLEAR 0x4000 #endif #ifndef PERL_PV_ESCAPE_RE # define PERL_PV_ESCAPE_RE 0x8000 #endif #ifndef PERL_PV_PRETTY_NOCLEAR # define PERL_PV_PRETTY_NOCLEAR PERL_PV_ESCAPE_NOCLEAR #endif #ifndef PERL_PV_PRETTY_DUMP # define PERL_PV_PRETTY_DUMP PERL_PV_PRETTY_ELLIPSES|PERL_PV_PRETTY_QUOTE #endif #ifndef PERL_PV_PRETTY_REGPROP # define PERL_PV_PRETTY_REGPROP PERL_PV_PRETTY_ELLIPSES|PERL_PV_PRETTY_LTGT|PERL_PV_ESCAPE_RE #endif /* Hint: pv_escape * Note that unicode functionality is only backported to * those perl versions that support it. For older perl * versions, the implementation will fall back to bytes. */ #ifndef pv_escape #if defined(NEED_pv_escape) static char * DPPP_(my_pv_escape)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, STRLEN * const escaped, const U32 flags); static #else extern char * DPPP_(my_pv_escape)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, STRLEN * const escaped, const U32 flags); #endif #ifdef pv_escape # undef pv_escape #endif #define pv_escape(a,b,c,d,e,f) DPPP_(my_pv_escape)(aTHX_ a,b,c,d,e,f) #define Perl_pv_escape DPPP_(my_pv_escape) #if defined(NEED_pv_escape) || defined(NEED_pv_escape_GLOBAL) char * DPPP_(my_pv_escape)(pTHX_ SV *dsv, char const * const str, const STRLEN count, const STRLEN max, STRLEN * const escaped, const U32 flags) { const char esc = flags & PERL_PV_ESCAPE_RE ? '%' : '\\'; const char dq = flags & PERL_PV_ESCAPE_QUOTE ? '"' : esc; char octbuf[32] = "%123456789ABCDF"; STRLEN wrote = 0; STRLEN chsize = 0; STRLEN readsize = 1; #if defined(is_utf8_string) && defined(utf8_to_uvchr) bool isuni = flags & PERL_PV_ESCAPE_UNI ? 1 : 0; #endif const char *pv = str; const char * const end = pv + count; octbuf[0] = esc; if (!(flags & PERL_PV_ESCAPE_NOCLEAR)) sv_setpvs(dsv, ""); #if defined(is_utf8_string) && defined(utf8_to_uvchr) if ((flags & PERL_PV_ESCAPE_UNI_DETECT) && is_utf8_string((U8*)pv, count)) isuni = 1; #endif for (; pv < end && (!max || wrote < max) ; pv += readsize) { const UV u = #if defined(is_utf8_string) && defined(utf8_to_uvchr) isuni ? utf8_to_uvchr((U8*)pv, &readsize) : #endif (U8)*pv; const U8 c = (U8)u & 0xFF; if (u > 255 || (flags & PERL_PV_ESCAPE_ALL)) { if (flags & PERL_PV_ESCAPE_FIRSTCHAR) chsize = my_snprintf(octbuf, sizeof octbuf, "%" UVxf, u); else chsize = my_snprintf(octbuf, sizeof octbuf, "%cx{%" UVxf "}", esc, u); } else if (flags & PERL_PV_ESCAPE_NOBACKSLASH) { chsize = 1; } else { if (c == dq || c == esc || !isPRINT(c)) { chsize = 2; switch (c) { case '\\' : /* fallthrough */ case '%' : if (c == esc) octbuf[1] = esc; else chsize = 1; break; case '\v' : octbuf[1] = 'v'; break; case '\t' : octbuf[1] = 't'; break; case '\r' : octbuf[1] = 'r'; break; case '\n' : octbuf[1] = 'n'; break; case '\f' : octbuf[1] = 'f'; break; case '"' : if (dq == '"') octbuf[1] = '"'; else chsize = 1; break; default: chsize = my_snprintf(octbuf, sizeof octbuf, pv < end && isDIGIT((U8)*(pv+readsize)) ? "%c%03o" : "%c%o", esc, c); } } else { chsize = 1; } } if (max && wrote + chsize > max) { break; } else if (chsize > 1) { sv_catpvn(dsv, octbuf, chsize); wrote += chsize; } else { char tmp[2]; my_snprintf(tmp, sizeof tmp, "%c", c); sv_catpvn(dsv, tmp, 1); wrote++; } if (flags & PERL_PV_ESCAPE_FIRSTCHAR) break; } if (escaped != NULL) *escaped= pv - str; return SvPVX(dsv); } #endif #endif #ifndef pv_pretty #if defined(NEED_pv_pretty) static char * DPPP_(my_pv_pretty)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, char const * const start_color, char const * const end_color, const U32 flags); static #else extern char * DPPP_(my_pv_pretty)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, char const * const start_color, char const * const end_color, const U32 flags); #endif #ifdef pv_pretty # undef pv_pretty #endif #define pv_pretty(a,b,c,d,e,f,g) DPPP_(my_pv_pretty)(aTHX_ a,b,c,d,e,f,g) #define Perl_pv_pretty DPPP_(my_pv_pretty) #if defined(NEED_pv_pretty) || defined(NEED_pv_pretty_GLOBAL) char * DPPP_(my_pv_pretty)(pTHX_ SV *dsv, char const * const str, const STRLEN count, const STRLEN max, char const * const start_color, char const * const end_color, const U32 flags) { const U8 dq = (flags & PERL_PV_PRETTY_QUOTE) ? '"' : '%'; STRLEN escaped; if (!(flags & PERL_PV_PRETTY_NOCLEAR)) sv_setpvs(dsv, ""); if (dq == '"') sv_catpvs(dsv, "\""); else if (flags & PERL_PV_PRETTY_LTGT) sv_catpvs(dsv, "<"); if (start_color != NULL) sv_catpv(dsv, D_PPP_CONSTPV_ARG(start_color)); pv_escape(dsv, str, count, max, &escaped, flags | PERL_PV_ESCAPE_NOCLEAR); if (end_color != NULL) sv_catpv(dsv, D_PPP_CONSTPV_ARG(end_color)); if (dq == '"') sv_catpvs(dsv, "\""); else if (flags & PERL_PV_PRETTY_LTGT) sv_catpvs(dsv, ">"); if ((flags & PERL_PV_PRETTY_ELLIPSES) && escaped < count) sv_catpvs(dsv, "..."); return SvPVX(dsv); } #endif #endif #ifndef pv_display #if defined(NEED_pv_display) static char * DPPP_(my_pv_display)(pTHX_ SV * dsv, const char * pv, STRLEN cur, STRLEN len, STRLEN pvlim); static #else extern char * DPPP_(my_pv_display)(pTHX_ SV * dsv, const char * pv, STRLEN cur, STRLEN len, STRLEN pvlim); #endif #ifdef pv_display # undef pv_display #endif #define pv_display(a,b,c,d,e) DPPP_(my_pv_display)(aTHX_ a,b,c,d,e) #define Perl_pv_display DPPP_(my_pv_display) #if defined(NEED_pv_display) || defined(NEED_pv_display_GLOBAL) char * DPPP_(my_pv_display)(pTHX_ SV *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim) { pv_pretty(dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP); if (len > cur && pv[cur] == '\0') sv_catpvs(dsv, "\\0"); return SvPVX(dsv); } #endif #endif #endif /* _P_P_PORTABILITY_H_ */ /* End of File ppport.h */ Net-LDNS-0.75/README.md000644 000770 000024 00000005100 12471046240 014567 0ustar00calledstaff000000 000000 Introduction ============ This module aims to provide an alternative to the Net::DNS module, based the ldns library from NLnet Labs (https://www.nlnetlabs.nl/projects/ldns/). The module includes the necessary C code, so the library does not need to be globally installed. It does, however, rely on a sufficiently recent version of OpenSSL being present. This module is written as part of the Zonemaster project (http://github.com/dotse/zonemaster), and therefore primarily exposes the functionality needed for that. Since Zonemaster is a diagnostic tool, that means the functions most used are those for looking things up and inspecting them. If you want a module that specifically aims to be a complete and transparent interface to ldns, DNS::LDNS is a better fit than this module. API === This module started as an alternative to Net::DNS. Thus, the interface is similar but not identical. The main difference at the moment is that the expected entrypoint to the system is through Net::LDNS directly rather than a submodule (like Net::DNS::Resolver). It's also not possible to set the flags in the resolver object at creation, although that may change. The API should at the moment be considered slightly volatile. We have other code written to the current interface, so it's unlikely that we'll want to make any drastic changes, but at least until we start calling it version 1.0 it's a good idea to check for changes before upgrading. IDN === If GNU libidn is installed when this module is compiled, it will be used to add a simple function that converts strings from Perl's internal encoding to IDNA domain name format. In order to convert strings from whatever encoding you have to Perl's internal format, use L. If you need any kind of control or options, use L. The included function here is only meant to assist in the most basic case, although that should cover a lot of real-world use cases. Installation ============ Installation uses the normal `perl Makefile.PL && make && make test && make install` sequence. This assumes that OpenSSL can be found in one of the places where the C compiler looks by default (if it's somewhere else, try using the `--prefix` flag when running `Makefile.PL`). `make test` assumes that it can send queries to the outside world. There is a small part in the code that may not be compatible with non-Unix operating systems, in that it assumes that the file /dev/null exists. If you try using this on Windows, VMS, z/OS or something else non-Unix, I'd love to hear from you so we can sort that bit out. /Calle Dybedahl , 12 February 2015Net-LDNS-0.75/src/000755 000770 000024 00000000000 12510741546 014110 5ustar00calledstaff000000 000000 Net-LDNS-0.75/t/000755 000770 000024 00000000000 12510741546 013564 5ustar00calledstaff000000 000000 Net-LDNS-0.75/t/axfr.t000644 000770 000024 00000001133 12352741045 014705 0ustar00calledstaff000000 000000 use Test::More; use Test::Fatal; BEGIN { use_ok( 'Net::LDNS' ) } my $res = Net::LDNS->new( '46.21.100.115' ); my $res2 = Net::LDNS->new( '192.36.144.107' ); my $counter = 0; my $return = $res->axfr( 'cyberpomo.com', sub { my ($rr) = @_; $counter += 1; if ($rr->type eq 'CNAME') { return 0; } else { return 1; } }); ok(!$return, 'Terminated early'); ok(($counter > 1), 'Saw more than one entry (' . $counter . ')'); like( exception { $res2->axfr( 'iis.se', sub { return 1 })}, qr/NOTAUTH/, 'Expected exception'); done_testing; Net-LDNS-0.75/t/dnssec.t000644 000770 000024 00000006103 12467344246 015237 0ustar00calledstaff000000 000000 use Test::More; BEGIN { use_ok( 'Net::LDNS' ); } my $key1 = Net::LDNS::RR->new( "iis.se. 2395 IN DNSKEY 257 3 5 AwEAAcq5u+qe5VibnyvSnGU20panweAk2QxflGVuVQhzQABQV4SIdAQs +LNVHF61lcxe504jhPmjeQ656X6t+dHpRz1DdPO/ukcIITjIRoJHqS+X XyL6gUluZoDU+K6vpxkGJx5m5n4boRTKCTUAR/9rw2+IQRRTtb6nBwsC 3pmf9IlJQjQMb1cQTb0UO7fYgXDZIYVul2LwGpKRrMJ6Ul1nepkSxTMw Q4H9iKE9FhqPeIpzU9dnXGtJ+ZCx9tWSZ9VsSLWBJtUwoE6ZfIoF1ioq qxfGl9JV1/6GkDxo3pMN2edhkp8aqoo/R+mrJYi0vE8jbXvhZ12151Dy wuSxbGjAlxk=" ); my $key2 = Net::LDNS::RR->new( "iis.se. 1591 IN DNSKEY 256 3 5 BQEAAAABuWpCewwMRD7yPzy6TGsymMAc82IHVGB+vjKVIAYKbPG7QxuLEtEzUxDJo09gLN2/N0OF+NnTkmDMj8KA+eIgtqmMuq5kdDVc+eSNLJZ0 am0o27UEkXmW20iV0d6B/KW1X1nufzBSaacUzkBKyDfK4cN3aVsYIDXT H7Jw1agEzrM=" ); my $soa = Net::LDNS::RR->new( "iis.se. 3600 IN SOA ns.nic.se. hostmaster.iis.se. 1384853101 10800 3600 1814400 14400" ); my $sig = Net::LDNS::RR->new( "iis.se. 3600 IN RRSIG SOA 5 2 3600 20131129082501 20131119082501 59213 iis.se. ShhhfRT82jfA/J1AAqiie/4r7JuiYOpK6dIwugOtlf0/UpVsOYEIukpe Bq9i7fsa0GNWz/o9gqF8DnsCHzgxZnAngTrJpZAlsrC/FP/6v8WfnFsP LDw9g6Ow8Z6TL9JmZr22YPp27Rwujdb5AnzdurEvQxIAqW66CCCy2pc9 //s=" ); is( $sig->keytag, $key2->keytag ); ok( !$sig->verify( [$soa], [ $key1, $key2 ] ), 'Signature does not verify (expired).' ); ok( !$sig->verify( [$soa], [$key1] ), 'Signature does not verify (wrong key).' ); is( $sig->verify_str( [$soa], [ $key1, $key2 ] ), 'DNSSEC signature has expired', 'Expected unsuccessful verification message.' ); is( $sig->verify_str( [$soa], [$key1] ), 'No keys with the keytag and algorithm from the RRSIG found', 'Expected unsuccessful verification message.' ); my $msg = ''; my $res = $sig->verify_time( [$soa], [ $key1, $key2 ], 1385628478, $msg ); ok( $res, 'Verified OK in the past.' ); is( $msg, 'All OK', 'Expected verification message' ); my $ds1 = $key1->ds( 'sha1' ); isa_ok( $ds1, 'Net::LDNS::RR::DS', 'sha1' ); ok( $ds1->verify( $key1 ) ) if $ds1; my $ds2 = $key1->ds( 'sha256' ); isa_ok( $ds2, 'Net::LDNS::RR::DS', 'sha256' ); ok( $ds2->verify( $key1 ) ) if $ds2; my $ds3 = $key1->ds( 'sha384' ); isa_ok( $ds3, 'Net::LDNS::RR::DS', 'sha384' ); ok( $ds3->verify( $key1 ) ) if $ds3; my $ds4 = $key1->ds( 'gost' ); if ( $ds4 ) { # We may not have GOST available. isa_ok( $ds4, 'Net::LDNS::RR::DS', 'gost' ); ok( $ds4->verify( $key1 ) ) if $ds4; } is($key1->keysize, 2048, 'Key is 2048 bits long'); is($key2->keysize, 1024, 'Key is 1024 bits long'); my $nsec = Net::LDNS::RR->new('xx.se. 7200 IN NSEC xx0r.se. NS RRSIG NSEC'); isa_ok($nsec, 'Net::LDNS::RR::NSEC'); ok($nsec->covers('xx-example.se'), 'Covers xx-example.se'); my $nsec3 = Net::LDNS::RR->new('NR2E513KM693MBTNVHH56ENF54F886T0.com. 86400 IN NSEC3 1 1 0 - NR2FUHQVR56LH70L6F971J3L6N1RH2TU NS DS RRSIG'); isa_ok($nsec3, 'Net::LDNS::RR::NSEC3'); ok($nsec3->covers('xx-example.com'), 'Covers xx-example.com'); $res = Net::LDNS->new( '194.146.106.22' ); $res->dnssec( 1 ); my $p1 = $res->query('www.iis.se', 'A'); ok( $p1->needs_edns, 'Needs EDNS0'); ok( $p1->has_edns, 'Alias is there'); ok( ($p1->edns_size > 0), 'EDNS0 size larger than zero' ); done_testing; Net-LDNS-0.75/t/example.org000644 000770 000024 00000001231 12411261230 015710 0ustar00calledstaff000000 000000 $ORIGIN . $TTL 86400 ; 1 day example.org IN SOA kennedy.example.org. hostmaster.example.org. ( 2014061900 ; serial 28800 ; refresh (8 hours) 7200 ; retry (2 hours) 604800 ; expire (1 week) 86400 ; minimum (1 day) ) NS ns2.example.net. NS kennedy.example.org. NS tara.example.org. NS illyria.example.org. MX 10 kennedy.example.org. $ORIGIN example.org. home A 183.68.21.31 staging CNAME kadath.example.net. willow A 179.199.7.2 www CNAME home tara A 109.174.1.145 kennedy A 146.121.6.227 sameen A 146.121.6.47 illyria A 146.121.0.115 illyria AAAA 2a02:70:4::44b spencer A 119.74.162.14 Net-LDNS-0.75/t/idn.t000644 000770 000024 00000001354 12506212323 014515 0ustar00calledstaff000000 000000 use Test::More; use Test::Fatal; use Encode; use Devel::Peek; use utf8; BEGIN { use_ok( "Net::LDNS" => qw[:all] ) } no warnings 'uninitialized'; if (exception {to_idn("whatever")} =~ /libidn not installed/) { ok(!has_idn(), 'No IDN'); done_testing; exit; } ok(has_idn(), 'Has IDN'); my $encoded = to_idn( 'annaröd.se' ); is( $encoded, 'xn--annard-0xa.se', 'One name encoded right' ); my @before = ('annaröd.se', 'rindlöw.se', 'räksmörgås.se', 'nic.中國', 'iis.se'); my @many = to_idn @before; is_deeply( \@many, [qw( xn--annard-0xa.se xn--rindlw-0xa.se xn--rksmrgs-5wao1o.se nic.xn--fiqz9s iis.se )], 'Many encoded right' ); like( exception { to_idn( "ö" x 63 ) }, qr/Punycode/, 'Boom today' ); done_testing; Net-LDNS-0.75/t/load_zonefile.t000644 000770 000024 00000000564 12415176111 016562 0ustar00calledstaff000000 000000 use Test::More; use Test::Fatal; use strict; use warnings; BEGIN { use_ok("Net::LDNS" => qw(load_zonefile))} my @rrs = load_zonefile("t/example.org"); is(scalar(@rrs), 16, 'All records loaded'); is($rrs[0]->type, 'SOA', 'SOA record first'); is($rrs[-1]->type, 'A', 'A record last'); is(lc($rrs[-1]->name), 'spencer.example.org.', 'Expected name last'); done_testing();Net-LDNS-0.75/t/netldns.t000644 000770 000024 00000010141 12502502027 015403 0ustar00calledstaff000000 000000 use Test::More; use Devel::Peek; use version; BEGIN { use_ok( 'Net::LDNS' ) } my $lib_v = version->parse(Net::LDNS::lib_version()); ok( $lib_v >= v1.6.16, 'ldns version at least 1.6.16' ); my $s = Net::LDNS->new( '8.8.8.8' ); isa_ok( $s, 'Net::LDNS' ); my $p = $s->query( 'nic.se', 'MX' ); isa_ok( $p, 'Net::LDNS::Packet' ); is( $p->rcode, 'NOERROR', 'expected rcode' ); my $p2 = $s->query( 'iis.se', 'NS', 'IN' ); isa_ok( $p2, 'Net::LDNS::Packet' ); is( $p2->rcode, 'NOERROR' ); is( $p2->opcode, 'QUERY', 'expected opcode' ); my $pround = Net::LDNS::Packet->new_from_wireformat( $p2->wireformat ); isa_ok( $pround, 'Net::LDNS::Packet' ); is( $pround->opcode, $p2->opcode, 'roundtrip opcode OK' ); is( $pround->rcode, $p2->rcode, 'roundtrip rcode OK' ); ok( $p2->id() > 0, 'packet ID set' ); ok( $p2->qr(), 'QR bit set' ); ok( !$p2->aa(), 'AA bit not set' ); ok( !$p2->tc(), 'TC bit not set' ); ok( $p2->rd(), 'RD bit set' ); ok( !$p2->cd(), 'CD bit not set' ); ok( $p2->ra(), 'RA bit set' ); ok( !$p2->ad(), 'AD bit not set' ); ok( !$p2->do(), 'DO bit not set' ); ok( $p2->querytime > 0 ); is( $p2->answerfrom, '8.8.8.8', 'expected answerfrom' ); $p2->answerfrom( '1.2.3.4' ); is( $p2->answerfrom, '1.2.3.4', 'setting answerfrom works' ); ok($p2->timestamp > 0, 'has a timestamp to begin with'); $p2->timestamp( 4711 ); is( $p2->timestamp, 4711, 'setting timestamp works' ); $p2->timestamp( 4711.4711 ); ok( $p2->timestamp - 4711.4711 < 0.0001, 'setting timestamp works with microseconds too' ); eval { $s->query( 'nic.se', 'gurksallad', 'CH' ) }; like( $@, qr/Unknown RR type: gurksallad/ ); eval { $s->query( 'nic.se', 'SOA', 'gurksallad' ) }; like( $@, qr/Unknown RR class: gurksallad/ ); eval { $s->query( 'nic.se', 'soa', 'IN' ) }; ok( !$@ ); my @answer = $p2->answer; is( scalar( @answer ), 3, 'expected number of NS records in answer' ); my %known_ns = map { $_ => 1 } qw[ns.nic.se. i.ns.se. ns3.nic.se.]; foreach my $rr ( @answer ) { isa_ok( $rr, 'Net::LDNS::RR::NS' ); is( lc($rr->owner), 'iis.se.', 'expected owner name' ); ok( $rr->ttl > 0, 'positive TTL (' . $rr->ttl . ')' ); is( $rr->type, 'NS', 'type is NS' ); is( $rr->class, 'IN', 'class is IN' ); ok( $known_ns{ lc($rr->nsdname) }, 'known nsdname (' . $rr->nsdname . ')' ); } my %known_mx = map { $_ => 1 } qw[mx1.iis.se. mx2.iis.se. ]; foreach my $rr ( $p->answer ) { is( $rr->preference, 10, 'expected MX preference' ); ok( $known_mx{ lc($rr->exchange) }, 'known MX exchange (' . $rr->exchange . ')' ); } my $lroot = Net::LDNS->new( '199.7.83.42' ); my $se = $lroot->query( 'se', 'NS' ); is( scalar( $se->question ), 1, 'one question' ); is( scalar( $se->answer ), 0, 'zero answers' ); is( scalar( $se->authority ), 9, 'nine authority' ); my $add = scalar( $se->additional ); ok( $add == 16 || $add == 15, 'sixteen additional' ); my $rr = Net::LDNS::RR->new_from_string( 'se. 172800 IN SOA catcher-in-the-rye.nic.se. registry-default.nic.se. 2013111305 1800 1800 864000 7200' ); my $rr2 = Net::LDNS::RR->new( 'se. 172800 IN TXT "SE zone update: 2013-11-13 15:08:28 +0000 (EPOCH 1384355308) (auto)"' ); ok( $se->unique_push( 'answer', $rr ), 'unique_push returns ok' ); is( $se->answer, 1, 'one record in answer section' ); ok( !$se->unique_push( 'answer', $rr ), 'unique_push returns false' ); is( $se->answer, 1, 'still one record in answer section' ); ok( $se->unique_push( 'ansWer', $rr2 ), 'unique_push returns ok again' ); is( $se->answer, 2, 'two records in answer section' ); my $made = Net::LDNS::Packet->new( 'foo.com', 'SOA', 'IN' ); isa_ok( $made, 'Net::LDNS::Packet' ); foreach my $flag (qw[do qr tc aa rd cd ra ad]) { ok(!$made->$flag(), uc($flag).' not set'); $made->$flag(1); ok($made->$flag(), uc($flag).' set'); } is($made->edns_size, 0, 'Initial EDNS0 UDP size is 0'); ok($made->edns_size(4096)); is($made->edns_size, 4096, 'EDNS0 UDP size set to 4096'); ok(!$made->edns_size(2**17), 'Setting to too big did not work'); # Too big is($made->edns_rcode, 0, 'Extended RCODE is 0'); $made->edns_rcode(1); is($made->edns_rcode, 1, 'Extended RCODE is 1'); is($made->type, 'answer'); done_testing; Net-LDNS-0.75/t/packet.t000644 000770 000024 00000001655 12413502756 015227 0ustar00calledstaff000000 000000 use Test::More; use Test::Fatal; use strict; use warnings; use_ok('Net::LDNS'); my $p = new_ok('Net::LDNS::Packet' => ['www.example.org', 'SOA', 'IN']); foreach my $r (qw[NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL REFUSED YXDOMAIN YXRRSET NXRRSET NOTAUTH NOTZONE]) { is($p->rcode($r), $r, $r); } like( exception {$p->rcode('gurksallad')}, qr/Unknown RCODE: gurksallad/, 'Expected exception' ); foreach my $r (qw[QUERY IQUERY STATUS NOTIFY UPDATE]) { is($p->opcode($r), $r, $r); } like( exception {$p->opcode('gurksallad')}, qr/Unknown OPCODE: gurksallad/, 'Expected exception' ); is($p->id(4711), 4711, 'Setting ID'); is($p->id(2147488359), 4711, 'Wraparound ID'); is($p->querytime(4711), 4711, 'Setting query time'); is($p->querytime(2147488359), 2147488359, 'Setting larger query time'); is($p->answerfrom, undef, 'No answerfrom'); $p->answerfrom('127.0.0.1'); is($p->answerfrom, '127.0.0.1', 'Localhost'); done_testing();Net-LDNS-0.75/t/regression.t000644 000770 000024 00000000441 12346573036 016134 0ustar00calledstaff000000 000000 use Test::More; use Test::Fatal; use strict; use warnings; BEGIN { use_ok("Net::LDNS")} my $s = Net::LDNS->new( '8.8.8.8' ); isa_ok( $s, 'Net::LDNS' ); like( exception { $s->query( 'xx--example..', 'A' ) }, qr/Invalid domain name: xx--example../, 'Died on invalid name'); done_testing;Net-LDNS-0.75/t/resolver.t000644 000770 000024 00000004557 12506264401 015620 0ustar00calledstaff000000 000000 use Test::More; use Net::LDNS; my $r = Net::LDNS->new( '8.8.8.8' ); $r->recurse( 0 ); ok( !$r->recurse, 'recursive off' ); $r->recurse( 1 ); ok( $r->recurse, 'recursive on' ); $r->retrans( 17 ); is( $r->retrans, 17, 'retrans set' ); $r->retry( 17 ); is( $r->retry, 17, 'retry set' ); $r->debug( 1 ); ok( $r->debug, 'debug set' ); $r->debug( 0 ); ok( !$r->debug, 'debug unset' ); $r->dnssec( 1 ); ok( $r->dnssec, 'dnssec set' ); $r->dnssec( 0 ); ok( !$r->dnssec, 'dnssec unset' ); $r->cd( 1 ); ok( $r->cd, 'dnssec set' ); $r->cd( 0 ); ok( !$r->cd, 'dnssec unset' ); $r->usevc( 1 ); ok( $r->usevc, 'usevc set' ); $r->usevc( 0 ); ok( !$r->usevc, 'usevc unset' ); $r->igntc( 1 ); ok( $r->igntc, 'igntc set' ); $r->igntc( 0 ); ok( !$r->igntc, 'igntc unset' ); $r->edns_size( 4711 ); is($r->edns_size, 4711 , 'ENDS0 UDP size set'); $r->edns_size( 0 ); is($r->edns_size, 0 , 'ENDS0 UDP size set to zero'); is($r->timeout, 5, 'Expected default timeout'); $r->timeout(3.33); ok(($r->timeout - 3.33) < 0.01, 'Expected set timeout'); my $addr = '192.0.2.1'; # Reserved RFC5737 ok($r->source($addr), "Source set."); is($r->source, $addr, 'Source got.'); subtest 'recursion' => sub { my $r = Net::LDNS->new( '8.8.4.4' ); my $p1 = $r->query( 'www.iis.se' ); is( scalar($p1->answer), 1); $r->recurse(0); my $p2 = $r->query( 'www.nic.se' ); is( scalar($p2->answer), 0, 'Got a reply'); ok(!$p2->rd, 'RD flag set'); }; subtest 'global' => sub { my $res = new_ok( 'Net::LDNS' ); my $p = eval { $res->query( 'www.iis.se' ) } ; if (not $p) { diag $@; } else { isa_ok( $p, 'Net::LDNS::Packet' ); isa_ok( $_, 'Net::LDNS::RR' ) for $p->answer; } }; # subtest 'sections' => sub { # my $res = Net::LDNS->new( '194.146.106.22' ); # my $p = eval { $res->query( 'www.iis.se' ) }; # plan skip_all => 'No response, cannot test' if not $p; # # is( scalar( $p->answer ), 1, 'answer count in scalar context' ); # is( scalar( $p->authority ), 3, 'authority count in scalar context' ); # is( scalar( $p->additional ), 6, 'additional count in scalar context' ); # is( scalar( $p->question ), 1, 'question count in scalar context' ); # }; subtest 'broken' => sub { my $b0rken = eval { Net::LDNS->new( 'gurksallad' ) }; ok( !$b0rken ); like( $@, qr/Failed to parse IP address: gurksallad/ ); }; done_testing; Net-LDNS-0.75/t/rr.t000644 000770 000024 00000015671 12415176374 014413 0ustar00calledstaff000000 000000 use Test::More; use Test::Fatal; use Devel::Peek; use MIME::Base64; BEGIN { use_ok( 'Net::LDNS' ) } my $s = Net::LDNS->new( '8.8.8.8' ); subtest 'rdf' => sub { my $p = $s->query( 'iis.se', 'SOA' ); plan skip_all => 'No response, cannot test' if not $p; foreach my $rr ( $p->answer ) { is( $rr->rd_count, 7 ); foreach my $n (0..($rr->rd_count-1)) { ok(length($rr->rdf($n)) >= 4); } like( exception { $rr->rdf(7) }, qr/Trying to fetch nonexistent RDATA at position/, 'died on overflow'); } }; subtest 'SOA' => sub { my $p = $s->query( 'iis.se', 'SOA' ); plan skip_all => 'No response, cannot test' if not $p; foreach my $rr ( $p->answer ) { isa_ok( $rr, 'Net::LDNS::RR::SOA' ); is( lc($rr->mname), 'ns.nic.se.' ); is( lc($rr->rname), 'hostmaster.iis.se.' ); ok( $rr->serial >= 1381471502, 'serial' ); is( $rr->refresh, 10800, 'refresh' ); is( $rr->retry, 3600, 'retry' ); is( $rr->expire, 1814400, 'expire' ); is( $rr->minimum, 14400, 'minimum' ); } }; subtest 'A' => sub { my $p = $s->query( 'a.ns.se' ); plan skip_all => 'No response, cannot test' if not $p; foreach my $rr ( $p->answer ) { isa_ok( $rr, 'Net::LDNS::RR::A' ); is( $rr->address, '192.36.144.107', 'expected address string' ); is( $rr->type, 'A' ); is( length($rr->rdf(0)), 4 ); } }; subtest 'AAAA' => sub { $p = $s->query( 'a.ns.se', 'AAAA' ); plan skip_all => 'No response, cannot test' if not $p; foreach my $rr ( $p->answer ) { isa_ok( $rr, 'Net::LDNS::RR::AAAA' ); is( $rr->address, '2a01:3f0:0:301::53', 'expected address string' ); is( length($rr->rdf(0)), 16 ); } }; subtest 'TXT' => sub { my $se = Net::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, 'Net::LDNS::RR::TXT' ); like( $rr->txtdata, qr/^"SE zone update: / ); } }; subtest 'DNSKEY' => sub { my $se = Net::LDNS->new( '192.36.144.107' ); my $pk = $se->query( 'se', 'DNSKEY' ); plan skip_all => 'No response, cannot test' if not $pk; foreach my $rr ( $pk->answer ) { isa_ok( $rr, 'Net::LDNS::RR::DNSKEY' ); ok( $rr->flags == 256 or $rr->flags == 257 ); is( $rr->protocol, 3 ); is( $rr->algorithm, 5 ); } }; subtest 'RRSIG' => sub { my $se = Net::LDNS->new( '192.36.144.107' ); my $pr = $se->query( 'se', 'RRSIG' ); plan skip_all => 'No response, cannot test' if not $pr; foreach my $rr ( $pr->answer ) { isa_ok( $rr, 'Net::LDNS::RR::RRSIG' ); is( $rr->signer, 'se.' ); is( $rr->labels, 1 ); if ( $rr->typecovered eq 'DNSKEY' ) { is( $rr->keytag, 59747 ); # .SE KSK should not change very often } } }; subtest 'NSEC' => sub { my $se = Net::LDNS->new( '192.36.144.107' ); my $pn = $se->query( 'se', 'NSEC' ); plan skip_all => 'No response, cannot test' if not $pn; foreach my $rr ( $pn->answer ) { isa_ok( $rr, 'Net::LDNS::RR::NSEC' ); ok( $rr->typehref->{TXT} ); ok( !$rr->typehref->{MX} ); ok( $rr->typehref->{TXT} ); is( $rr->typelist, 'NS SOA TXT RRSIG NSEC DNSKEY ' ); } }; subtest 'From string' => sub { my $made = Net::LDNS::RR->new_from_string( 'nic.se IN NS a.ns.se' ); isa_ok( $made, 'Net::LDNS::RR::NS' ); my $made2 = Net::LDNS::RR->new_from_string( 'nic.se IN NS a.ns.se' ); is( $made->compare( $made2 ), 0, 'direct comparison works' ); my $made3 = Net::LDNS::RR->new_from_string( 'mic.se IN NS a.ns.se' ); my $made4 = Net::LDNS::RR->new_from_string( 'oic.se IN NS a.ns.se' ); is( $made->compare( $made3 ), 1, 'direct comparison works' ); is( $made->compare( $made4 ), -1, 'direct comparison works' ); is( $made eq $made2, 1, 'indirect comparison works' ); is( $made <=> $made3, 1, 'indirect comparison works' ); is( $made cmp $made4, -1, 'indirect comparison works' ); is( "$made", "nic.se. 3600 IN NS a.ns.se." ); }; subtest 'DS' => sub { my $se = Net::LDNS->new( '192.36.144.107' ); my $pd = $se->query( 'nic.se', 'DS' ); plan skip_all => 'No response, cannot test' if not $pd; my $nic_key = Net::LDNS::RR->new( 'nic.se IN DNSKEY 257 3 5 AwEAAdhJAx197qFpGGXuQn8XH0tQpQSfjvLKMcreRvJyO+f3F3weIHR3 6E8DObolHFp+m1YkxsgnHYjUFN4E9sKa38ZXU0oHTSsB3adExJkINA/t INDlKrzUDn4cIbyUCqHNGe0et+lHmjmfZdj62GJlHgVmxizYkoBd7Rg0 wxzEOo7CA3ZadaHuqmVJ2HvqRCoe+5NDsYpnDia7WggvLTe0vorV6kDc u6d5N9AUPwBsR7YUkbetfXMtUebux71kHCGUJdmzp84MeDi9wXYIssjR oTC5wUF2H3I2Mnj5GqdyBwQCdj5otFbRAx3jiMD+ROxXJxOFdFq7fWi1 yPqUf1jpJ+8=' ); my $made = Net::LDNS::RR->new_from_string( 'nic.se IN NS a.ns.se' ); foreach my $rr ( $pd->answer ) { isa_ok( $rr, 'Net::LDNS::RR::DS' ); is( $rr->keytag, 16696 ); is( $rr->algorithm, 5 ); ok( $rr->digtype == 1 or $rr->digtype == 2 ); ok( $rr->hexdigest eq '40079ddf8d09e7f10bb248a69b6630478a28ef969dde399f95bc3b39f8cbacd7' or $rr->hexdigest eq 'ef5d421412a5eaf1230071affd4f585e3b2b1a60' ); ok( $rr->verify( $nic_key ), 'derived from expected DNSKEY' ); ok( !$rr->verify( $made ), 'does not match a non-DS non-DNSKEY record' ); } }; subtest 'NSEC3' => sub { my $nsec3 = Net::LDNS::RR->new_from_string( 'VD0J8N54V788IUBJL9CN5MUD416BS5I6.com. 86400 IN NSEC3 1 1 0 - VD0N3HDL5MG940MOUBCF5MNLKGDT9RFT NS DS RRSIG' ); isa_ok( $nsec3, 'Net::LDNS::RR::NSEC3' ); is( $nsec3->algorithm, 1 ); is( $nsec3->flags, 1 ); ok( $nsec3->optout ); is( $nsec3->iterations, 0 ); is( $nsec3->salt, undef ); is( encode_base64( $nsec3->next_owner ), "FPtBccW1LaCSAtjy2PLa9aQb1O39\n" ); is( $nsec3->typelist, 'NS DS RRSIG ' ); is_deeply( [ sort keys %{ $nsec3->typehref } ], [qw(DS NS RRSIG)] ); }; subtest 'NSEC3PARAM' => sub { my $nsec3param = Net::LDNS::RR->new_from_string( 'whitehouse.gov. 3600 IN NSEC3PARAM 1 0 1 B2C19AB526819347' ); isa_ok( $nsec3param, 'Net::LDNS::RR::NSEC3PARAM' ); is( $nsec3param->algorithm, 1 ); is( $nsec3param->flags, 0 ); is( $nsec3param->iterations, 1, "Iterations" ); is( encode_base64( $nsec3param->salt ), "CLLBmrUmgZNH\n", "Salt" ); is( lc($nsec3param->owner), 'whitehouse.gov.' ); }; subtest 'SRV' => sub { my $srv = Net::LDNS::RR->new( '_nicname._tcp.se. 172800 IN SRV 0 0 43 whois.nic-se.se.' ); is( $srv->type, 'SRV' ); }; subtest 'SPF' => sub { my $spf = Net::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, 'Net::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"' ); }; done_testing; Net-LDNS-0.75/t/rrlist.t000644 000770 000024 00000001670 12257303517 015274 0ustar00calledstaff000000 000000 use Test::More; use Devel::Peek; use Net::LDNS; my $s = Net::LDNS->new( '8.8.8.8' ); my $p = $s->query( 'iis.se', 'SOA' ); my $rrl = $p->all; isa_ok( $rrl, 'Net::LDNS::RRList' ); is( $rrl->count, 1, 'one RR in list' ); my $rr = $rrl->pop; isa_ok( $rr, 'Net::LDNS::RR::SOA' ); is( $rrl->count, 0, 'zero RRs in list' ); my $rr1 = Net::LDNS::RR->new_from_string( 'nic.se IN NS a.ns.se' ); my $rr2 = Net::LDNS::RR->new_from_string( 'mic.se IN NS a.ns.se' ); my $rr3 = Net::LDNS::RR->new_from_string( 'nic.se IN NS b.ns.se' ); ok( $rrl->push( $rr1 ), 'Push OK' ); ok( $rrl->push( $rr3 ), 'Second push OK' ); ok( $rrl->is_rrset, 'Is an RRset' ); ok( $rrl->push( $rr2 ), 'Third push OK' ); is( $rrl->count, 3, 'Three RRs in list' ); ok( !$rrl->is_rrset, 'Is not an RRset' ); while ( my $rr = $rrl->pop ) { isa_ok( $rr, 'Net::LDNS::RR::NS' ); } is( $rrl->count, 0, 'zero RRs in list' ); ok( !$rrl->is_rrset, 'Is not an RRset' ); done_testing; Net-LDNS-0.75/t/serialize.t000644 000770 000024 00000001037 12413002756 015734 0ustar00calledstaff000000 000000 use Test::More; use JSON::PP; use_ok( 'Net::LDNS' ); my $p = Net::LDNS::Packet->new( 'www.iis.se', 'A', 'IN' ); $p->answerfrom( '127.0.0.1' ); $p->timestamp( '1384423749.28615' ); my $json = JSON::PP->new->allow_blessed->convert_blessed; my $ref = decode_json $json->encode( $p ); is( $ref->{'Net::LDNS::Packet'}{answerfrom}, '127.0.0.1' ); my $decode = JSON::PP->new->filter_json_single_key_object( 'Net::LDNS::Packet' => sub { is $_[0]->{answerfrom}, '127.0.0.1'; return; } ); $decode->decode( $json->encode( $p ) ); done_testing; Net-LDNS-0.75/t/threads.t000644 000770 000024 00000001327 12502554215 015402 0ustar00calledstaff000000 000000 use Test::More; use_ok('Net::LDNS'); my $can_use_threads = eval 'use threads; 1'; if ($can_use_threads) { my $resolver = Net::LDNS->new('8.8.8.8'); isa_ok($resolver, 'Net::LDNS'); my $rr = Net::LDNS::RR->new('www.iis.se. 60 IN A 91.226.36.46'); isa_ok($rr, 'Net::LDNS::RR::A'); my $p = $resolver->query('www.google.com'); isa_ok($p, 'Net::LDNS::Packet'); my $rrlist = $p->all; isa_ok($rrlist, 'Net::LDNS::RRList'); threads->create( sub { my $p = $resolver->query('www.lysator.liu.se'); if (not ($p and ref($p) and ref($p) eq 'Net::LDNS::Packet')) { die "Something is wrong here"; } } ) for 1..5; $_->join for threads->list; } done_testing;Net-LDNS-0.75/t/utils.t000644 000770 000024 00000001042 12415176303 015103 0ustar00calledstaff000000 000000 use Test::More; BEGIN { use_ok( 'Net::LDNS' ) } my $res = new_ok( 'Net::LDNS', ['8.8.4.4'] ); my @addrs = sort $res->name2addr( 'b.ns.se' ); my $count = $res->name2addr( 'b.ns.se' ); is_deeply( \@addrs, [ "192.36.133.107", "2001:67c:254c:301::53" ], 'expected addresses' ); is( $count, 2, 'expected count' ); my @names = sort $res->addr2name( '8.8.8.8' ); $count = $res->addr2name( '8.8.8.8' ); is_deeply( [map {lc($_)} @names], ['google-public-dns-a.google.com.'], 'expected names' ); is( $count, 1, 'expected name count' ); done_testing; Net-LDNS-0.75/src/assist.c000644 000770 000024 00000010721 12503753676 015574 0ustar00calledstaff000000 000000 #include #ifdef USE_ITHREADS #define RESOLVER_HASH_NAME "Net::LDNS::__resolvers__" #define RR_HASH_NAME "Net::LDNS::__rrs__" #define RRLIST_HASH_NAME "Net::LDNS::__rrlists__" #define PACKET_HASH_NAME "Net::LDNS::__packets__" void net_ldns_forget() { int i; const char *names[] = { RESOLVER_HASH_NAME, RR_HASH_NAME, RRLIST_HASH_NAME, PACKET_HASH_NAME, NULL }; for(i=0; names[i]; i++) { HV *hash; HE *entry; hash = get_hv(names[i], GV_ADD); while ( (entry = hv_iternext(hash)) != NULL ) { SV *val = hv_iterval(hash, entry); if(!SvOK(val)) { SV *key = hv_iterkeysv(entry); hv_delete_ent(hash, key, G_DISCARD, 0); } } } } void net_ldns_remember_resolver(SV *rv) { net_ldns_remember(rv, RESOLVER_HASH_NAME); } void net_ldns_remember_rr(SV *rv) { net_ldns_remember(rv, RR_HASH_NAME); } void net_ldns_remember_rrlist(SV *rv) { net_ldns_remember(rv, RRLIST_HASH_NAME); } void net_ldns_remember_packet(SV *rv) { net_ldns_remember(rv, PACKET_HASH_NAME); } void net_ldns_remember(SV *rv, const char *hashname) { HV *hash; SV *val; STRLEN keylen; char *keystr; hash = get_hv(hashname, GV_ADD); val = newRV_inc(SvRV(rv)); keystr = SvPV(val,keylen); sv_rvweaken(val); hv_store(hash, keystr, keylen, val, 0); } void net_ldns_clone_resolvers() { HV *hash; HE *entry; hash = get_hv(RESOLVER_HASH_NAME, GV_ADD); hv_iterinit(hash); while ( (entry = hv_iternext(hash)) != NULL ) { SV *val = hv_iterval(hash, entry); if(SvOK(val)) { ldns_resolver *old = INT2PTR(ldns_resolver *, SvIV((SV *)SvRV(val))); ldns_resolver *new = ldns_resolver_clone(old); sv_setiv_mg(SvRV(val), PTR2IV(new)); } else { SV *key = hv_iterkeysv(entry); hv_delete_ent(hash, key, G_DISCARD, 0); } } } void net_ldns_clone_rrs() { HV *hash; HE *entry; hash = get_hv(RR_HASH_NAME, GV_ADD); hv_iterinit(hash); while ( (entry = hv_iternext(hash)) != NULL ) { SV *val = hv_iterval(hash, entry); SV *key = hv_iterkeysv(entry); if(SvOK(val)) { ldns_rr *old = INT2PTR(ldns_rr *, SvIV((SV *)SvRV(val))); ldns_rr *new = ldns_rr_clone(old); sv_setiv_mg(SvRV(val), PTR2IV(new)); } else { hv_delete_ent(hash, key, G_DISCARD, 0); } } } void net_ldns_clone_rrlists() { HV *hash; HE *entry; hash = get_hv(RRLIST_HASH_NAME, GV_ADD); hv_iterinit(hash); while ( (entry = hv_iternext(hash)) != NULL ) { SV *val = hv_iterval(hash, entry); if(SvOK(val)) { ldns_rr_list *old = INT2PTR(ldns_rr_list *, SvIV((SV *)SvRV(val))); ldns_rr_list *new = ldns_rr_list_clone(old); sv_setiv_mg(SvRV(val), PTR2IV(new)); } else { SV *key = hv_iterkeysv(entry); hv_delete_ent(hash, key, G_DISCARD, 0); } } } void net_ldns_clone_packets() { HV *hash; HE *entry; hash = get_hv(PACKET_HASH_NAME, GV_ADD); hv_iterinit(hash); while ( (entry = hv_iternext(hash)) != NULL ) { SV *val = hv_iterval(hash, entry); if(SvOK(val)) { ldns_pkt *old = INT2PTR(ldns_pkt *, SvIV((SV *)SvRV(val))); ldns_pkt *new = ldns_pkt_clone(old); sv_setiv_mg(SvRV(val), PTR2IV(new)); } else { SV *key = hv_iterkeysv(entry); hv_delete_ent(hash, key, G_DISCARD, 0); } } } #endif char * randomize_capitalization(char *in) { #ifdef RANDOMIZE char *str; str = in; while(*str) { if(Drand01() < 0.5) { *str = tolower(*str); } else { *str = toupper(*str); } str++; } #endif return in; } SV * rr2sv(ldns_rr *rr) { char rrclass[30]; char *type; type = ldns_rr_type2str(ldns_rr_get_type(rr)); snprintf(rrclass, 30, "Net::LDNS::RR::%s", type); SV* rr_sv = newSV(0); if (strncmp(type, "TYPE", 4)==0) { sv_setref_pv(rr_sv, "Net::LDNS::RR", rr); } else { sv_setref_pv(rr_sv, rrclass, rr); } free(type); #ifdef USE_ITHREADS net_ldns_remember_rr(rr_sv); #endif return rr_sv; } Net-LDNS-0.75/src/ldns/000755 000770 000024 00000000000 12510741546 015050 5ustar00calledstaff000000 000000 Net-LDNS-0.75/src/LDNS.xs000644 000770 000024 00000144017 12506263755 015241 0ustar00calledstaff000000 000000 #include MODULE = Net::LDNS PACKAGE = Net::LDNS PROTOTYPES: ENABLE SV * to_idn(...) PPCODE: { #ifdef WE_CAN_HAZ_IDN int i; for( i = 0; i1) { SvGETMAGIC(ST(1)); ldns_resolver_set_recursive(obj, SvIV(ST(1))); } RETVAL = ldns_resolver_recursive(obj); OUTPUT: RETVAL bool debug(obj,...) Net::LDNS obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_resolver_set_debug(obj, SvIV(ST(1))); } RETVAL = ldns_resolver_debug(obj); OUTPUT: RETVAL bool dnssec(obj,...) Net::LDNS obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_resolver_set_dnssec(obj, SvIV(ST(1))); } RETVAL = ldns_resolver_dnssec(obj); OUTPUT: RETVAL bool cd(obj,...) Net::LDNS obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_resolver_set_dnssec_cd(obj, SvIV(ST(1))); } RETVAL = ldns_resolver_dnssec_cd(obj); OUTPUT: RETVAL bool usevc(obj,...) Net::LDNS obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_resolver_set_usevc(obj, SvIV(ST(1))); } RETVAL = ldns_resolver_usevc(obj); OUTPUT: RETVAL bool igntc(obj,...) Net::LDNS obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_resolver_set_igntc(obj, SvIV(ST(1))); } RETVAL = ldns_resolver_igntc(obj); OUTPUT: RETVAL U8 retry(obj,...) Net::LDNS obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_resolver_set_retry(obj, SvIV(ST(1))); } RETVAL = ldns_resolver_retry(obj); OUTPUT: RETVAL U8 retrans(obj,...) Net::LDNS obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_resolver_set_retrans(obj, SvIV(ST(1))); } RETVAL = ldns_resolver_retrans(obj); OUTPUT: RETVAL U16 edns_size(obj,...) Net::LDNS obj; CODE: if( items > 1 ) { SvGETMAGIC(ST(1)); ldns_resolver_set_edns_udp_size(obj, (U16)SvIV(ST(1))); } RETVAL = ldns_resolver_edns_udp_size(obj); OUTPUT: RETVAL U16 port(obj,...) Net::LDNS obj; CODE: if( items > 1 ) { SvGETMAGIC(ST(1)); ldns_resolver_set_port(obj, (U16)SvIV(ST(1))); } RETVAL = ldns_resolver_port(obj); OUTPUT: RETVAL SV * name2addr(obj,name) Net::LDNS obj; const char *name; PPCODE: { ldns_rr_list *addrs; ldns_rdf *dname; size_t n, i; I32 context; context = GIMME_V; if(context == G_VOID) { XSRETURN_NO; } dname = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, name); if(dname==NULL) { croak("Name error for '%s'", name); } addrs = ldns_get_rr_list_addr_by_name(obj,dname,LDNS_RR_CLASS_IN,0); n = ldns_rr_list_rr_count(addrs); ldns_rdf_deep_free(dname); if (context == G_SCALAR) { ldns_rr_list_deep_free(addrs); XSRETURN_IV(n); } else { for(i = 0; i < n; ++i) { ldns_rr *rr = ldns_rr_list_rr(addrs,i); ldns_rdf *addr_rdf = ldns_rr_a_address(rr); char *addr_str = ldns_rdf2str(addr_rdf); SV* sv = newSVpv(addr_str,0); mXPUSHs(sv); free(addr_str); } ldns_rr_list_deep_free(addrs); } } SV * addr2name(obj,addr_in) Net::LDNS obj; const char *addr_in; PPCODE: { ldns_rr_list *names; ldns_rdf *addr_rdf; size_t n, i; I32 context; context = GIMME_V; if(context == G_VOID) { XSRETURN_NO; } addr_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, addr_in); if(addr_rdf==NULL) { addr_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, addr_in); } if(addr_rdf==NULL) { croak("Failed to parse address: %s", addr_in); } names = ldns_get_rr_list_name_by_addr(obj,addr_rdf,LDNS_RR_CLASS_IN,0); ldns_rdf_deep_free(addr_rdf); n = ldns_rr_list_rr_count(names); if (context == G_SCALAR) { ldns_rr_list_deep_free(names); XSRETURN_IV(n); } else { for(i = 0; i < n; ++i) { ldns_rr *rr = ldns_rr_list_rr(names,i); ldns_rdf *name_rdf = ldns_rr_rdf(rr,0); char *name_str = randomize_capitalization(ldns_rdf2str(name_rdf)); SV* sv = newSVpv(name_str,0); mXPUSHs(sv); free(name_str); } ldns_rr_list_deep_free(names); } } bool axfr(obj,dname,callback,class="IN") Net::LDNS obj; const char *dname; SV *callback; const char *class; CODE: { ldns_rdf *domain = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, dname); ldns_rr_class cl = ldns_get_rr_class_by_name(class); ldns_status status; SvGETMAGIC(callback); if(SvTYPE(SvRV(callback)) != SVt_PVCV) { ldns_rdf_deep_free(domain); croak("Callback not a code reference"); } if(domain==NULL) { ldns_rdf_deep_free(domain); croak("Name error for '%s", dname); } if(!cl) { ldns_rdf_deep_free(domain); croak("Unknown RR class: %s", class); } status = ldns_axfr_start(obj, domain, cl); ldns_rdf_deep_free(domain); if(status != LDNS_STATUS_OK) { croak("AXFR setup error: %s", ldns_get_errorstr_by_id(status)); } RETVAL = 1; while (!ldns_axfr_complete(obj)) { int count; SV *ret; ldns_rr *rr = ldns_axfr_next(obj); if(rr==NULL) { ldns_pkt *pkt = ldns_axfr_last_pkt(obj); if(pkt != NULL) { char tmp[20]; char *msg = ldns_pkt_rcode2str(ldns_pkt_get_rcode(pkt)); strncpy(tmp,msg,19); free(msg); croak("AXFR transfer error: %s", tmp); } else { croak("AXFR transfer error: unknown problem"); } ldns_pkt_free(pkt); } /* Enter the Cargo Cult */ ENTER; SAVETMPS; PUSHMARK(SP); mXPUSHs(rr2sv(rr)); PUTBACK; count = call_sv(callback, G_SCALAR); SPAGAIN; if(count != 1) { croak("Callback did not return exactly one value in scalar context"); } ret = POPs; if(!SvTRUE(ret)) { RETVAL = 0; break; } PUTBACK; FREETMPS; LEAVE; /* Callback magic ends */ } ldns_axfr_abort(obj); } OUTPUT: RETVAL bool axfr_start(obj,dname,class="IN") Net::LDNS obj; const char *dname; const char *class; CODE: { ldns_rdf *domain = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, dname); ldns_rr_class cl = ldns_get_rr_class_by_name(class); ldns_status s; if(domain==NULL) { croak("Name error for '%s", dname); } if(!cl) { croak("Unknown RR class: %s", class); } s = ldns_axfr_start(obj, domain, cl); RETVAL = (s==LDNS_STATUS_OK); } OUTPUT: RETVAL SV * axfr_next(obj) Net::LDNS obj; CODE: { ldns_rr *rr; /* ldns unfortunately prints to standard error, so close it while we call them */ /* EDIT: That behavior should be changed starting with ldns 1.6.17, but we'll keep the closing for a while */ int err_fd = fileno(stderr); /* Remember fd for stderr */ int save_fd = dup(err_fd); /* Copy open fd for stderr */ int tmp_fd; fflush(stderr); /* Print anything waiting */ tmp_fd = open("/dev/null",O_RDWR); /* Open something to allocate the now-free fd stderr used */ dup2(tmp_fd,err_fd); rr = ldns_axfr_next(obj); /* Shut up */ close(tmp_fd); /* Close the placeholder */ fflush(stderr); /* Flush anything ldns buffered */ dup2(save_fd,err_fd); /* And copy the open stderr back to where it should be */ if(rr==NULL) { croak("AXFR error"); } RETVAL = rr2sv(rr); } OUTPUT: RETVAL bool axfr_complete(obj) Net::LDNS obj; CODE: RETVAL = ldns_axfr_complete(obj); OUTPUT: RETVAL Net::LDNS::Packet axfr_last_packet(obj) Net::LDNS obj; CODE: RETVAL = ldns_axfr_last_pkt(obj); OUTPUT: RETVAL double timeout(obj,...) Net::LDNS obj; CODE: struct timeval tv; if( items > 1) { double dec_part, int_part; struct timeval tn; SvGETMAGIC(ST(1)); dec_part = modf(SvNV(ST(1)), &int_part); tn.tv_sec = int_part; tn.tv_usec = 1000000*dec_part; ldns_resolver_set_timeout(obj, tn); } tv = ldns_resolver_timeout(obj); RETVAL = (double)tv.tv_sec; RETVAL += ((double)tv.tv_usec)/1000000; OUTPUT: RETVAL char * source(obj,...) Net::LDNS obj; CODE: if(items >= 2) { ldns_rdf *address; SvGETMAGIC(ST(1)); address = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, SvPV_nolen(ST(1))); if(address == NULL) { address = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, SvPV_nolen(ST(1))); } if(address == NULL) { croak("Failed to parse IP address: %s", SvPV_nolen(ST(1))); } ldns_resolver_set_source(obj, address); } RETVAL = ldns_rdf2str(ldns_resolver_source(obj)); OUTPUT: RETVAL CLEANUP: free(RETVAL); void DESTROY(obj) Net::LDNS obj; CODE: #ifdef USE_ITHREADS net_ldns_forget(); #endif ldns_axfr_abort(obj); ldns_resolver_deep_free(obj); #ifdef USE_ITHREADS void CLONE(class) char *class; CODE: net_ldns_clone_resolvers(); #endif MODULE = Net::LDNS PACKAGE = Net::LDNS::Packet PREFIX=packet_ SV * packet_new(objclass,name,type="A",class="IN") char *objclass; char *name; char *type; char *class; CODE: { ldns_rdf *rr_name; ldns_rr_type rr_type; ldns_rr_class rr_class; ldns_pkt *pkt; rr_type = ldns_get_rr_type_by_name(type); if(!rr_type) { croak("Unknown RR type: %s", type); } rr_class = ldns_get_rr_class_by_name(class); if(!rr_class) { croak("Unknown RR class: %s", class); } rr_name = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, name); if(rr_name == NULL) { croak("Name error for '%s'", name); } pkt = ldns_pkt_query_new(rr_name, rr_type, rr_class,0); RETVAL = newSV(0); sv_setref_pv(RETVAL, objclass, pkt); #ifdef USE_ITHREADS net_ldns_remember_packet(RETVAL); #endif } OUTPUT: RETVAL char * packet_rcode(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); if ( strnEQ("NOERROR", SvPV_nolen(ST(1)), 7) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_NOERROR); } else if ( strnEQ("FORMERR", SvPV_nolen(ST(1)), 7) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_FORMERR); } else if ( strnEQ("SERVFAIL", SvPV_nolen(ST(1)), 8) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_SERVFAIL); } else if ( strnEQ("NXDOMAIN", SvPV_nolen(ST(1)), 8) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_NXDOMAIN); } else if ( strnEQ("NOTIMPL", SvPV_nolen(ST(1)), 7) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_NOTIMPL); } else if ( strnEQ("REFUSED", SvPV_nolen(ST(1)), 7) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_REFUSED); } else if ( strnEQ("YXDOMAIN", SvPV_nolen(ST(1)), 8) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_YXDOMAIN); } else if ( strnEQ("YXRRSET", SvPV_nolen(ST(1)), 7) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_YXRRSET); } else if ( strnEQ("NXRRSET", SvPV_nolen(ST(1)), 7) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_NXRRSET); } else if ( strnEQ("NOTAUTH", SvPV_nolen(ST(1)), 7) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_NOTAUTH); } else if ( strnEQ("NOTZONE", SvPV_nolen(ST(1)), 7) ) { ldns_pkt_set_rcode(obj, LDNS_RCODE_NOTZONE); } else { croak("Unknown RCODE: %s", SvPV_nolen(ST(1))); } } RETVAL = ldns_pkt_rcode2str(ldns_pkt_get_rcode(obj)); OUTPUT: RETVAL CLEANUP: free(RETVAL); char * packet_opcode(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); if ( strnEQ("QUERY", SvPV_nolen(ST(1)), 5) ) { ldns_pkt_set_opcode(obj, LDNS_PACKET_QUERY); } else if ( strnEQ("IQUERY", SvPV_nolen(ST(1)), 6) ) { ldns_pkt_set_opcode(obj, LDNS_PACKET_IQUERY); } else if ( strnEQ("STATUS", SvPV_nolen(ST(1)), 6) ) { ldns_pkt_set_opcode(obj, LDNS_PACKET_STATUS); } else if ( strnEQ("NOTIFY", SvPV_nolen(ST(1)), 6) ) { ldns_pkt_set_opcode(obj, LDNS_PACKET_NOTIFY); } else if ( strnEQ("UPDATE", SvPV_nolen(ST(1)), 6) ) { ldns_pkt_set_opcode(obj, LDNS_PACKET_UPDATE); } else { croak("Unknown OPCODE: %s", SvPV_nolen(ST(1))); } } RETVAL = ldns_pkt_opcode2str(ldns_pkt_get_opcode(obj)); OUTPUT: RETVAL CLEANUP: free(RETVAL); U16 packet_id(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_pkt_set_id(obj, (U16)SvIV(ST(1))); } RETVAL = ldns_pkt_id(obj); OUTPUT: RETVAL bool packet_qr(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_pkt_set_qr(obj, SvIV(ST(1))); } RETVAL = ldns_pkt_qr(obj); OUTPUT: RETVAL bool packet_aa(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_pkt_set_aa(obj, SvIV(ST(1))); } RETVAL = ldns_pkt_aa(obj); OUTPUT: RETVAL bool packet_tc(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_pkt_set_tc(obj, SvIV(ST(1))); } RETVAL = ldns_pkt_tc(obj); OUTPUT: RETVAL bool packet_rd(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_pkt_set_rd(obj, SvIV(ST(1))); } RETVAL = ldns_pkt_rd(obj); OUTPUT: RETVAL bool packet_cd(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_pkt_set_cd(obj, SvIV(ST(1))); } RETVAL = ldns_pkt_cd(obj); OUTPUT: RETVAL bool packet_ra(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_pkt_set_ra(obj, SvIV(ST(1))); } RETVAL = ldns_pkt_ra(obj); OUTPUT: RETVAL bool packet_ad(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_pkt_set_ad(obj, SvIV(ST(1))); } RETVAL = ldns_pkt_ad(obj); OUTPUT: RETVAL bool packet_do(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_pkt_set_edns_do(obj, SvIV(ST(1))); } RETVAL = ldns_pkt_edns_do(obj); OUTPUT: RETVAL size_t packet_size(obj) Net::LDNS::Packet obj; CODE: RETVAL = ldns_pkt_size(obj); OUTPUT: RETVAL U32 packet_querytime(obj,...) Net::LDNS::Packet obj; CODE: if ( items > 1 ) { SvGETMAGIC(ST(1)); ldns_pkt_set_querytime(obj, (U32)SvIV(ST(1))); } RETVAL = ldns_pkt_querytime(obj); OUTPUT: RETVAL char * packet_answerfrom(obj,...) Net::LDNS::Packet obj; CODE: if(items >= 2) { ldns_rdf *address; SvGETMAGIC(ST(1)); address = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, SvPV_nolen(ST(1))); if(address == NULL) { address = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, SvPV_nolen(ST(1))); } if(address == NULL) { croak("Failed to parse IP address: %s", SvPV_nolen(ST(1))); } ldns_pkt_set_answerfrom(obj, address); } RETVAL = ldns_rdf2str(ldns_pkt_answerfrom(obj)); OUTPUT: RETVAL CLEANUP: free(RETVAL); double packet_timestamp(obj,...) Net::LDNS::Packet obj; CODE: if(items >= 2) { struct timeval tn; double dec_part, int_part; SvGETMAGIC(ST(1)); dec_part = modf(SvNV(ST(1)), &int_part); tn.tv_sec = int_part; tn.tv_usec = 1000000*dec_part; ldns_pkt_set_timestamp(obj,tn); } struct timeval t = ldns_pkt_timestamp(obj); RETVAL = (double)t.tv_sec; RETVAL += ((double)t.tv_usec)/1000000; OUTPUT: RETVAL SV * packet_answer(obj) Net::LDNS::Packet obj; PPCODE: { size_t i,n; ldns_rr_list *rrs; I32 context = GIMME_V; if (context == G_VOID) { return; } rrs = ldns_pkt_answer(obj); n = ldns_rr_list_rr_count(rrs); if (context == G_SCALAR) { XSRETURN_IV(n); } for(i = 0; i < n; ++i) { mXPUSHs(rr2sv(ldns_rr_clone(ldns_rr_list_rr(rrs,i)))); } } SV * packet_authority(obj) Net::LDNS::Packet obj; PPCODE: { size_t i,n; ldns_rr_list *rrs; I32 context = GIMME_V; if (context == G_VOID) { return; } rrs = ldns_pkt_authority(obj); n = ldns_rr_list_rr_count(rrs); if (context == G_SCALAR) { XSRETURN_IV(n); } for(i = 0; i < n; ++i) { mXPUSHs(rr2sv(ldns_rr_clone(ldns_rr_list_rr(rrs,i)))); } } SV * packet_additional(obj) Net::LDNS::Packet obj; PPCODE: { size_t i,n; ldns_rr_list *rrs; I32 context = GIMME_V; if (context == G_VOID) { return; } rrs = ldns_pkt_additional(obj); n = ldns_rr_list_rr_count(rrs); if (context == G_SCALAR) { XSRETURN_IV(n); } for(i = 0; i < n; ++i) { mXPUSHs(rr2sv(ldns_rr_clone(ldns_rr_list_rr(rrs,i)))); } } SV * packet_question(obj) Net::LDNS::Packet obj; PPCODE: { size_t i,n; ldns_rr_list *rrs; I32 context = GIMME_V; if (context == G_VOID) { return; } rrs = ldns_pkt_question(obj); n = ldns_rr_list_rr_count(rrs); if (context == G_SCALAR) { XSRETURN_IV(n); } for(i = 0; i < n; ++i) { mXPUSHs(rr2sv(ldns_rr_clone(ldns_rr_list_rr(rrs,i)))); } } bool packet_unique_push(obj,section,rr) Net::LDNS::Packet obj; char *section; Net::LDNS::RR rr; CODE: { ldns_pkt_section sec; char lbuf[21]; char *p; p = lbuf; strncpy(lbuf, section, 20); for(; *p; p++) *p = tolower(*p); if(strncmp(lbuf, "answer", 6)==0) { sec = LDNS_SECTION_ANSWER; } else if(strncmp(lbuf, "additional", 10)==0) { sec = LDNS_SECTION_ADDITIONAL; } else if(strncmp(lbuf, "authority", 9)==0) { sec = LDNS_SECTION_AUTHORITY; } else if(strncmp(lbuf, "question", 8)==0) { sec = LDNS_SECTION_QUESTION; } else { croak("Unknown section: %s", section); } RETVAL = ldns_pkt_safe_push_rr(obj, sec, ldns_rr_clone(rr)); } OUTPUT: RETVAL SV * packet_all(obj) Net::LDNS::Packet obj; CODE: ldns_rr_list *list = ldns_pkt_all_noquestion(obj); RETVAL = sv_setref_pv(newSV(0), "Net::LDNS::RRList", list); #ifdef USE_ITHREADS net_ldns_remember_rrlist(RETVAL); #endif OUTPUT: RETVAL char * packet_string(obj) Net::LDNS::Packet obj; CODE: RETVAL = ldns_pkt2str(obj); RETVAL[strlen(RETVAL)-1] = '\0'; OUTPUT: RETVAL CLEANUP: free(RETVAL); SV * packet_wireformat(obj) Net::LDNS::Packet obj; CODE: { size_t sz; uint8_t *buf; ldns_status status; status = ldns_pkt2wire(&buf, obj, &sz); if(status != LDNS_STATUS_OK) { croak("Failed to produce wire format: %s", ldns_get_errorstr_by_id(status)); } else { RETVAL = newSVpvn((const char *)buf,sz); free(buf); } } OUTPUT: RETVAL SV * packet_new_from_wireformat(class,buf) char *class; SV *buf; CODE: { Net__LDNS__Packet pkt; ldns_status status; SvGETMAGIC(buf); status = ldns_wire2pkt(&pkt, (const uint8_t *)SvPV_nolen(buf), SvCUR(buf)); if(status != LDNS_STATUS_OK) { croak("Failed to parse wire format: %s", ldns_get_errorstr_by_id(status)); } else { RETVAL = newSV(0); sv_setref_pv(RETVAL, class, pkt); #ifdef USE_ITHREADS net_ldns_remember_packet(RETVAL); #endif } } OUTPUT: RETVAL U16 packet_edns_size(obj,...) Net::LDNS::Packet obj; CODE: if(items>=2) { SvGETMAGIC(ST(1)); ldns_pkt_set_edns_udp_size(obj, (U16)SvIV(ST(1))); } RETVAL = ldns_pkt_edns_udp_size(obj); OUTPUT: RETVAL U8 packet_edns_rcode(obj,...) Net::LDNS::Packet obj; CODE: if(items>=2) { SvGETMAGIC(ST(1)); ldns_pkt_set_edns_extended_rcode(obj, (U8)SvIV(ST(1))); } RETVAL = ldns_pkt_edns_extended_rcode(obj); OUTPUT: RETVAL U8 packet_edns_version(obj,...) Net::LDNS::Packet obj; CODE: if(items>=2) { SvGETMAGIC(ST(1)); ldns_pkt_set_edns_version(obj, (U8)SvIV(ST(1))); } RETVAL = ldns_pkt_edns_version(obj); OUTPUT: RETVAL bool packet_needs_edns(obj) Net::LDNS::Packet obj; ALIAS: Net::LDNS::Packet::has_edns = 1 CODE: RETVAL = ldns_pkt_edns(obj); OUTPUT: RETVAL SV * packet_type(obj) Net::LDNS::Packet obj; CODE: ldns_pkt_type type = ldns_pkt_reply_type(obj); switch (type){ case LDNS_PACKET_QUESTION: RETVAL = newSVpvs_share("question"); break; case LDNS_PACKET_REFERRAL: RETVAL = newSVpvs_share("referral"); break; case LDNS_PACKET_ANSWER: RETVAL = newSVpvs_share("answer"); break; case LDNS_PACKET_NXDOMAIN: RETVAL = newSVpvs_share("nxdomain"); break; case LDNS_PACKET_NODATA: RETVAL = newSVpvs_share("nodata"); break; case LDNS_PACKET_UNKNOWN: RETVAL = newSVpvs_share("unknown"); break; default: croak("Packet type is not even unknown"); } OUTPUT: RETVAL void packet_DESTROY(sv) SV *sv; CODE: #ifdef USE_ITHREADS net_ldns_forget(); #endif SvGETMAGIC(sv); ldns_pkt *obj = INT2PTR(ldns_pkt *, SvIV((SV *)SvRV(sv))); ldns_pkt_free(obj); #ifdef USE_ITHREADS void packet_CLONE(class) char *class; CODE: net_ldns_clone_packets(); #endif MODULE = Net::LDNS PACKAGE = Net::LDNS::RRList PREFIX=rrlist_ size_t rrlist_count(obj) Net::LDNS::RRList obj; CODE: RETVAL = ldns_rr_list_rr_count(obj); OUTPUT: RETVAL SV * rrlist_pop(obj) Net::LDNS::RRList obj; CODE: ldns_rr *rr = ldns_rr_list_pop_rr(obj); if(rr==NULL) { RETVAL = &PL_sv_no; } else { RETVAL = rr2sv(rr); } OUTPUT: RETVAL bool rrlist_push(obj,rr) Net::LDNS::RRList obj; Net::LDNS::RR rr; CODE: RETVAL = ldns_rr_list_push_rr(obj,ldns_rr_clone(rr)); OUTPUT: RETVAL bool rrlist_is_rrset(obj) Net::LDNS::RRList obj; CODE: RETVAL = ldns_is_rrset(obj); OUTPUT: RETVAL void rrlist_DESTROY(obj) Net::LDNS::RRList obj; CODE: #ifdef USE_ITHREADS net_ldns_forget(); #endif ldns_rr_list_deep_free(obj); #ifdef USE_ITHREADS void rrlist_CLONE(class) char *class; CODE: net_ldns_clone_rrlists(); #endif MODULE = Net::LDNS PACKAGE = Net::LDNS::RR PREFIX=rr_ SV * rr_new_from_string(class,str) char *class; char *str; PPCODE: ldns_status s; ldns_rr *rr; char rrclass[40]; char *rrtype; SV* rr_sv; s = ldns_rr_new_frm_str(&rr, str, 0, NULL, NULL); if(s != LDNS_STATUS_OK) { croak("Failed to build RR: %s", ldns_get_errorstr_by_id(s)); } rrtype = ldns_rr_type2str(ldns_rr_get_type(rr)); snprintf(rrclass, 39, "Net::LDNS::RR::%s", rrtype); free(rrtype); rr_sv = sv_newmortal(); sv_setref_pv(rr_sv, rrclass, rr); #ifdef USE_ITHREADS net_ldns_remember_rr(rr_sv); #endif PUSHs(rr_sv); char * rr_owner(obj) Net::LDNS::RR obj; CODE: RETVAL = randomize_capitalization(ldns_rdf2str(ldns_rr_owner(obj))); OUTPUT: RETVAL CLEANUP: free(RETVAL); U32 rr_ttl(obj) Net::LDNS::RR obj; CODE: RETVAL = ldns_rr_ttl(obj); OUTPUT: RETVAL char * rr_type(obj) Net::LDNS::RR obj; CODE: RETVAL = ldns_rr_type2str(ldns_rr_get_type(obj)); OUTPUT: RETVAL CLEANUP: free(RETVAL); char * rr_class(obj) Net::LDNS::RR obj; CODE: RETVAL = ldns_rr_class2str(ldns_rr_get_class(obj)); OUTPUT: RETVAL CLEANUP: free(RETVAL); char * rr_string(obj) Net::LDNS::RR obj; CODE: RETVAL = ldns_rr2str(obj); RETVAL[strlen(RETVAL)-1] = '\0'; OUTPUT: RETVAL CLEANUP: free(RETVAL); I32 rr_compare(obj1,obj2) Net::LDNS::RR obj1; Net::LDNS::RR obj2; CODE: RETVAL = ldns_rr_compare(obj1,obj2); OUTPUT: RETVAL size_t rr_rd_count(obj) Net::LDNS::RR obj; CODE: RETVAL = ldns_rr_rd_count(obj); OUTPUT: RETVAL SV * rr_rdf(obj,n) Net::LDNS::RR obj; size_t n; CODE: ldns_rdf *rdf = ldns_rr_rdf(obj,n); if(rdf==NULL) { croak("Trying to fetch nonexistent RDATA at position %lu", n); } RETVAL = newSVpvn((char*)ldns_rdf_data(rdf), ldns_rdf_size(rdf)); OUTPUT: RETVAL void rr_DESTROY(obj) Net::LDNS::RR obj; CODE: #ifdef USE_ITHREADS net_ldns_forget(); #endif ldns_rr_free(obj); #ifdef USE_ITHREADS void rr_CLONE(class) char *class; CODE: if(strEQ(class,"Net::LDNS::RR")) { net_ldns_clone_rrs(); } #endif MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::NS PREFIX=rr_ns_ char * rr_ns_nsdname(obj) Net::LDNS::RR::NS obj; CODE: RETVAL = randomize_capitalization(ldns_rdf2str(ldns_rr_rdf(obj, 0))); OUTPUT: RETVAL CLEANUP: free(RETVAL); MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::MX PREFIX=rr_mx_ U16 rr_mx_preference(obj) Net::LDNS::RR::MX obj; CODE: RETVAL = D_U16(obj, 0); OUTPUT: RETVAL char * rr_mx_exchange(obj) Net::LDNS::RR::MX obj; CODE: RETVAL = randomize_capitalization(D_STRING(obj, 1)); OUTPUT: RETVAL CLEANUP: free(RETVAL); MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::A PREFIX=rr_a_ char * rr_a_address(obj) Net::LDNS::RR::A obj; CODE: RETVAL = D_STRING(obj,0); OUTPUT: RETVAL CLEANUP: free(RETVAL); MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::AAAA PREFIX=rr_aaaa_ char * rr_aaaa_address(obj) Net::LDNS::RR::AAAA obj; CODE: RETVAL = D_STRING(obj,0); OUTPUT: RETVAL CLEANUP: free(RETVAL); MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::SOA PREFIX=rr_soa_ char * rr_soa_mname(obj) Net::LDNS::RR::SOA obj; CODE: RETVAL = randomize_capitalization(D_STRING(obj,0)); OUTPUT: RETVAL CLEANUP: free(RETVAL); char * rr_soa_rname(obj) Net::LDNS::RR::SOA obj; CODE: RETVAL = randomize_capitalization(D_STRING(obj,1)); OUTPUT: RETVAL CLEANUP: free(RETVAL); U32 rr_soa_serial(obj) Net::LDNS::RR::SOA obj; CODE: RETVAL = D_U32(obj,2); OUTPUT: RETVAL U32 rr_soa_refresh(obj) Net::LDNS::RR::SOA obj; CODE: RETVAL = D_U32(obj,3); OUTPUT: RETVAL U32 rr_soa_retry(obj) Net::LDNS::RR::SOA obj; CODE: RETVAL = D_U32(obj,4); OUTPUT: RETVAL U32 rr_soa_expire(obj) Net::LDNS::RR::SOA obj; CODE: RETVAL = D_U32(obj,5); OUTPUT: RETVAL U32 rr_soa_minimum(obj) Net::LDNS::RR::SOA obj; CODE: RETVAL = D_U32(obj,6); OUTPUT: RETVAL MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::DS PREFIX=rr_ds_ U16 rr_ds_keytag(obj) Net::LDNS::RR::DS obj; CODE: RETVAL = D_U16(obj,0); OUTPUT: RETVAL U8 rr_ds_algorithm(obj) Net::LDNS::RR::DS obj; CODE: RETVAL = D_U8(obj,1); OUTPUT: RETVAL U8 rr_ds_digtype(obj) Net::LDNS::RR::DS obj; CODE: RETVAL = D_U8(obj,2); OUTPUT: RETVAL SV * rr_ds_digest(obj) Net::LDNS::RR::DS obj; CODE: { ldns_rdf *rdf = ldns_rr_rdf(obj,3); RETVAL = newSVpvn((char*)ldns_rdf_data(rdf), ldns_rdf_size(rdf)); } OUTPUT: RETVAL char * rr_ds_hexdigest(obj) Net::LDNS::RR::DS obj; CODE: RETVAL = D_STRING(obj,3); OUTPUT: RETVAL CLEANUP: free(RETVAL); bool rr_ds_verify(obj,other) Net::LDNS::RR::DS obj; Net::LDNS::RR other; CODE: RETVAL = ldns_rr_compare_ds(obj, other); OUTPUT: RETVAL MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::DNSKEY PREFIX=rr_dnskey_ U32 rr_dnskey_keysize(obj) Net::LDNS::RR::DNSKEY obj; CODE: { U8 algorithm = D_U8(obj,2); ldns_rdf *rdf = ldns_rr_rdf(obj,3); uint8_t *data = ldns_rdf_data(rdf); size_t total = ldns_rdf_size(rdf); /* RSA variants */ if(algorithm==1||algorithm==5||algorithm==7||algorithm==8||algorithm==10) { size_t ex_len; if(data[0] == 0) { ex_len = 3+(U16)data[1]; } else { ex_len = 1+(U8)data[0]; } RETVAL = 8*(total-ex_len); } /* DSA variants */ else if(algorithm==3||algorithm==6) { RETVAL = (U8)data[0]; /* First octet is T value */ } /* Diffie-Hellman */ else if(algorithm==2) { RETVAL = (U16)data[4]; } /* No idea what this is */ else { RETVAL = 0; } } OUTPUT: RETVAL U16 rr_dnskey_flags(obj) Net::LDNS::RR::DNSKEY obj; CODE: RETVAL = D_U16(obj,0); OUTPUT: RETVAL U8 rr_dnskey_protocol(obj) Net::LDNS::RR::DNSKEY obj; CODE: RETVAL = D_U8(obj,1); OUTPUT: RETVAL U8 rr_dnskey_algorithm(obj) Net::LDNS::RR::DNSKEY obj; CODE: RETVAL = D_U8(obj,2); OUTPUT: RETVAL SV * rr_dnskey_keydata(obj) Net::LDNS::RR::DNSKEY obj; CODE: { ldns_rdf *rdf = ldns_rr_rdf(obj,3); RETVAL = newSVpvn((char*)ldns_rdf_data(rdf), ldns_rdf_size(rdf)); } OUTPUT: RETVAL U16 rr_dnskey_keytag(obj) Net::LDNS::RR::DNSKEY obj; CODE: RETVAL = ldns_calc_keytag(obj); OUTPUT: RETVAL Net::LDNS::RR::DS rr_dnskey_ds(obj, hash) Net::LDNS::RR::DNSKEY obj; const char *hash; CODE: { char lbuf[21]; char *p; ldns_hash htype; p = lbuf; strncpy(lbuf, hash, 20); for(; *p; p++) *p = tolower(*p); if(strEQ(lbuf,"sha1")) { htype = LDNS_SHA1; } else if(strEQ(lbuf, "sha256")) { htype = LDNS_SHA256; } else if(strEQ(lbuf, "sha384")) { htype = LDNS_SHA384; } else if(strEQ(lbuf,"gost")) { htype = LDNS_HASH_GOST; } else { croak("Unknown hash type: %s", hash); } RETVAL = ldns_key_rr2ds(obj,htype); } OUTPUT: RETVAL MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::RRSIG PREFIX=rr_rrsig_ char * rr_rrsig_typecovered(obj) Net::LDNS::RR::RRSIG obj; CODE: RETVAL = D_STRING(obj,0); OUTPUT: RETVAL CLEANUP: free(RETVAL); U8 rr_rrsig_algorithm(obj) Net::LDNS::RR::RRSIG obj; CODE: RETVAL = D_U8(obj,1); OUTPUT: RETVAL U8 rr_rrsig_labels(obj) Net::LDNS::RR::RRSIG obj; CODE: RETVAL = D_U8(obj,2); OUTPUT: RETVAL U32 rr_rrsig_origttl(obj) Net::LDNS::RR::RRSIG obj; CODE: RETVAL = D_U32(obj,3); OUTPUT: RETVAL U32 rr_rrsig_expiration(obj) Net::LDNS::RR::RRSIG obj; CODE: RETVAL = D_U32(obj,4); OUTPUT: RETVAL U32 rr_rrsig_inception(obj) Net::LDNS::RR::RRSIG obj; CODE: RETVAL = D_U32(obj,5); OUTPUT: RETVAL U16 rr_rrsig_keytag(obj) Net::LDNS::RR::RRSIG obj; CODE: RETVAL = D_U16(obj,6); OUTPUT: RETVAL char * rr_rrsig_signer(obj) Net::LDNS::RR::RRSIG obj; CODE: RETVAL = D_STRING(obj,7); OUTPUT: RETVAL CLEANUP: free(RETVAL); SV * rr_rrsig_signature(obj) Net::LDNS::RR::RRSIG obj; CODE: { ldns_rdf *rdf = ldns_rr_rdf(obj,8); RETVAL = newSVpvn((char*)ldns_rdf_data(rdf), ldns_rdf_size(rdf)); } OUTPUT: RETVAL bool rr_rrsig_verify_time(obj,rrset_in,keys_in, when, msg) Net::LDNS::RR::RRSIG obj; AV *rrset_in; AV *keys_in; time_t when; const char *msg; CODE: { size_t i; ldns_status s; ldns_rr_list *rrset = ldns_rr_list_new(); ldns_rr_list *keys = ldns_rr_list_new(); ldns_rr_list *sig = ldns_rr_list_new(); ldns_rr_list *good = ldns_rr_list_new(); if(av_len(rrset_in)==-1) { croak("RRset is empty"); } if(av_len(keys_in)==-1) { croak("Key list is empty"); } /* Make a list with only the RRSIG */ ldns_rr_list_push_rr(sig, obj); /* Take RRs out of the array and stick in a list */ for(i = 0; i <= av_len(rrset_in); ++i) { ldns_rr *rr; SV **rrsv = av_fetch(rrset_in,i,1); if (rrsv != NULL) { SvGETMAGIC(*rrsv); IV tmp = SvIV((SV*)SvRV(*rrsv)); rr = INT2PTR(ldns_rr *,tmp); if(rr != NULL) { ldns_rr_list_push_rr(rrset, rr); } } } /* Again, for the keys */ for(i = 0; i <= av_len(keys_in); ++i) { ldns_rr *rr; SV **rrsv = av_fetch(keys_in,i,1); IV tmp = SvIV((SV*)SvRV(*rrsv)); rr = INT2PTR(ldns_rr *,tmp); if(rr != NULL) { ldns_rr_list_push_rr(keys, rr); } } /* And verify using the lists */ s = ldns_verify_time(rrset, sig, keys, when, good); RETVAL = (s == LDNS_STATUS_OK); msg = ldns_get_errorstr_by_id(s); ldns_rr_list_free(rrset); ldns_rr_list_free(keys); ldns_rr_list_free(sig); ldns_rr_list_free(good); } OUTPUT: RETVAL msg MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::NSEC PREFIX=rr_nsec_ char * rr_nsec_next(obj) Net::LDNS::RR::NSEC obj; CODE: RETVAL = randomize_capitalization(D_STRING(obj,0)); OUTPUT: RETVAL char * rr_nsec_typelist(obj) Net::LDNS::RR::NSEC obj; CODE: RETVAL = D_STRING(obj,1); OUTPUT: RETVAL CLEANUP: free(RETVAL); SV * rr_nsec_typehref(obj) Net::LDNS::RR::NSEC obj; CODE: { char *typestring = D_STRING(obj,1); char *copy = typestring; size_t pos; HV *res = newHV(); pos = 0; while(typestring[pos] != '\0') { pos++; if(typestring[pos] == ' ') { typestring[pos] = '\0'; if(hv_store(res,typestring,pos,newSViv(1),0)==NULL) { croak("Failed to store to hash"); } typestring += pos+1; pos = 0; } } RETVAL = newRV_noinc((SV *)res); free(copy); } OUTPUT: RETVAL bool rr_nsec_covers(obj,name) Net::LDNS::RR::NSEC obj; const char *name; CODE: ldns_rdf *dname = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, name); ldns_dname2canonical(dname); ldns_rr2canonical(obj); RETVAL = ldns_nsec_covers_name(obj,dname); ldns_rdf_deep_free(dname); OUTPUT: RETVAL MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::NSEC3 PREFIX=rr_nsec3_ U8 rr_nsec3_algorithm(obj) Net::LDNS::RR::NSEC3 obj; CODE: RETVAL = ldns_nsec3_algorithm(obj); OUTPUT: RETVAL U8 rr_nsec3_flags(obj) Net::LDNS::RR::NSEC3 obj; CODE: RETVAL = ldns_nsec3_flags(obj); OUTPUT: RETVAL bool rr_nsec3_optout(obj) Net::LDNS::RR::NSEC3 obj; CODE: RETVAL = ldns_nsec3_optout(obj); OUTPUT: RETVAL U16 rr_nsec3_iterations(obj) Net::LDNS::RR::NSEC3 obj; CODE: RETVAL = ldns_nsec3_iterations(obj); OUTPUT: RETVAL SV * rr_nsec3_salt(obj) Net::LDNS::RR::NSEC3 obj; PPCODE: if(ldns_nsec3_salt_length(obj) > 0) { ldns_rdf *buf = ldns_nsec3_salt(obj); ST(0) = sv_2mortal(newSVpvn((char *)ldns_rdf_data(buf), ldns_rdf_size(buf))); ldns_rdf_deep_free(buf); } SV * rr_nsec3_next_owner(obj) Net::LDNS::RR::NSEC3 obj; CODE: ldns_rdf *buf = ldns_nsec3_next_owner(obj); RETVAL = newSVpvn((char *)ldns_rdf_data(buf), ldns_rdf_size(buf)); OUTPUT: RETVAL char * rr_nsec3_typelist(obj) Net::LDNS::RR::NSEC3 obj; CODE: RETVAL = ldns_rdf2str(ldns_nsec3_bitmap(obj)); OUTPUT: RETVAL CLEANUP: free(RETVAL); SV * rr_nsec3_typehref(obj) Net::LDNS::RR::NSEC3 obj; CODE: { char *typestring = ldns_rdf2str(ldns_nsec3_bitmap(obj)); char *copy = typestring; size_t pos; HV *res = newHV(); pos = 0; while(typestring[pos] != '\0') { pos++; if(typestring[pos] == ' ') { typestring[pos] = '\0'; if(hv_store(res,typestring,pos,newSViv(1),0)==NULL) { croak("Failed to store to hash"); } typestring += pos+1; pos = 0; } } RETVAL = newRV_noinc((SV *)res); free(copy); } OUTPUT: RETVAL bool rr_nsec3_covers(obj,name) Net::LDNS::RR::NSEC3 obj; const char *name; CODE: { ldns_rr *clone; ldns_rdf *dname; ldns_rdf *hashed; ldns_rdf *chopped; clone = ldns_rr_clone(obj); dname = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, name); ldns_dname2canonical(dname); ldns_rr2canonical(clone); hashed = ldns_nsec3_hash_name_frm_nsec3(clone, dname); chopped = ldns_dname_left_chop(dname); ldns_rdf_deep_free(dname); ldns_dname_cat(hashed,chopped); RETVAL = ldns_nsec_covers_name(clone,hashed); ldns_rdf_deep_free(hashed); ldns_rdf_deep_free(chopped); ldns_rr_free(clone); } OUTPUT: RETVAL MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::NSEC3PARAM PREFIX=rr_nsec3param_ U8 rr_nsec3param_algorithm(obj) Net::LDNS::RR::NSEC3PARAM obj; CODE: RETVAL = D_U8(obj,0); OUTPUT: RETVAL U8 rr_nsec3param_flags(obj) Net::LDNS::RR::NSEC3PARAM obj; CODE: RETVAL = D_U8(obj,1); OUTPUT: RETVAL U16 rr_nsec3param_iterations(obj) Net::LDNS::RR::NSEC3PARAM obj; CODE: RETVAL = D_U16(obj,2); OUTPUT: RETVAL SV * rr_nsec3param_salt(obj) Net::LDNS::RR::NSEC3PARAM obj; PPCODE: ldns_rdf *rdf = ldns_rr_rdf(obj,3); if(ldns_rdf_size(rdf) > 0) { mPUSHs(newSVpvn((char *)ldns_rdf_data(rdf), ldns_rdf_size(rdf))); } MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::PTR PREFIX=rr_ptr_ char * rr_ptr_ptrdname(obj) Net::LDNS::RR::PTR obj; CODE: RETVAL = randomize_capitalization(D_STRING(obj,0)); OUTPUT: RETVAL CLEANUP: free(RETVAL); MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::CNAME PREFIX=rr_cname_ char * rr_cname_cname(obj) Net::LDNS::RR::CNAME obj; CODE: RETVAL = randomize_capitalization(D_STRING(obj,0)); OUTPUT: RETVAL CLEANUP: free(RETVAL); MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::TXT PREFIX=rr_txt_ char * rr_txt_txtdata(obj) Net::LDNS::RR::TXT obj; CODE: RETVAL = D_STRING(obj,0); OUTPUT: RETVAL CLEANUP: free(RETVAL); MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::SPF PREFIX=rr_spf_ char * rr_spf_spfdata(obj) Net::LDNS::RR::SPF obj; CODE: RETVAL = D_STRING(obj,0); OUTPUT: RETVAL CLEANUP: free(RETVAL); MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::KEY PREFIX=rr_key_ U16 rr_key_flags(obj) Net::LDNS::RR::KEY obj; CODE: RETVAL = D_U16(obj,0); OUTPUT: RETVAL U8 rr_key_protocol(obj) Net::LDNS::RR::KEY obj; CODE: RETVAL = D_U8(obj,1); OUTPUT: RETVAL U8 rr_key_algorithm(obj) Net::LDNS::RR::KEY obj; CODE: RETVAL = D_U8(obj,2); OUTPUT: RETVAL SV * rr_key_keydata(obj) Net::LDNS::RR::KEY obj; CODE: { ldns_rdf *rdf = ldns_rr_rdf(obj,3); RETVAL = newSVpvn((char*)ldns_rdf_data(rdf), ldns_rdf_size(rdf)); } OUTPUT: RETVAL MODULE = Net::LDNS PACKAGE = Net::LDNS::RR::SIG PREFIX=rr_sig_ char * rr_sig_typecovered(obj) Net::LDNS::RR::SIG obj; CODE: RETVAL = D_STRING(obj,0); OUTPUT: RETVAL CLEANUP: free(RETVAL); U8 rr_sig_algorithm(obj) Net::LDNS::RR::SIG obj; CODE: RETVAL = D_U8(obj,1); OUTPUT: RETVAL U8 rr_sig_labels(obj) Net::LDNS::RR::SIG obj; CODE: RETVAL = D_U8(obj,2); OUTPUT: RETVAL U32 rr_sig_origttl(obj) Net::LDNS::RR::SIG obj; CODE: RETVAL = D_U32(obj,3); OUTPUT: RETVAL U32 rr_sig_expiration(obj) Net::LDNS::RR::SIG obj; CODE: RETVAL = D_U32(obj,4); OUTPUT: RETVAL U32 rr_sig_inception(obj) Net::LDNS::RR::SIG obj; CODE: RETVAL = D_U32(obj,5); OUTPUT: RETVAL U16 rr_sig_keytag(obj) Net::LDNS::RR::SIG obj; CODE: RETVAL = D_U16(obj,6); OUTPUT: RETVAL char * rr_sig_signer(obj) Net::LDNS::RR::SIG obj; CODE: RETVAL = D_STRING(obj,7); OUTPUT: RETVAL CLEANUP: free(RETVAL); SV * rr_sig_signature(obj) Net::LDNS::RR::SIG obj; CODE: { ldns_rdf *rdf = ldns_rr_rdf(obj,8); RETVAL = newSVpvn((char*)ldns_rdf_data(rdf), ldns_rdf_size(rdf)); } OUTPUT: RETVAL Net-LDNS-0.75/src/typemap000644 000770 000024 00000005074 12246050724 015515 0ustar00calledstaff000000 000000 Net::LDNS T_PTROBJ Net::LDNS::Packet T_PTROBJ Net::LDNS::RRList T_PTROBJ Net::LDNS::RR T_PTROBJ Net::LDNS::RR::A T_PTROBJ Net::LDNS::RR::A6 T_PTROBJ Net::LDNS::RR::AAAA T_PTROBJ Net::LDNS::RR::AFSDB T_PTROBJ Net::LDNS::RR::APL T_PTROBJ Net::LDNS::RR::ATMA T_PTROBJ Net::LDNS::RR::CAA T_PTROBJ Net::LDNS::RR::CDS T_PTROBJ Net::LDNS::RR::CERT T_PTROBJ Net::LDNS::RR::CNAME T_PTROBJ Net::LDNS::RR::DHCID T_PTROBJ Net::LDNS::RR::DLV T_PTROBJ Net::LDNS::RR::DNAME T_PTROBJ Net::LDNS::RR::DNSKEY T_PTROBJ Net::LDNS::RR::DS T_PTROBJ Net::LDNS::RR::EID T_PTROBJ Net::LDNS::RR::EUI48 T_PTROBJ Net::LDNS::RR::EUI64 T_PTROBJ Net::LDNS::RR::GID T_PTROBJ Net::LDNS::RR::GPOS T_PTROBJ Net::LDNS::RR::HINFO T_PTROBJ Net::LDNS::RR::HIP T_PTROBJ Net::LDNS::RR::IPSECKEY T_PTROBJ Net::LDNS::RR::ISDN T_PTROBJ Net::LDNS::RR::KEY T_PTROBJ Net::LDNS::RR::KX T_PTROBJ Net::LDNS::RR::L32 T_PTROBJ Net::LDNS::RR::L64 T_PTROBJ Net::LDNS::RR::LOC T_PTROBJ Net::LDNS::RR::LP T_PTROBJ Net::LDNS::RR::MAILA T_PTROBJ Net::LDNS::RR::MAILB T_PTROBJ Net::LDNS::RR::MB T_PTROBJ Net::LDNS::RR::MD T_PTROBJ Net::LDNS::RR::MF T_PTROBJ Net::LDNS::RR::MG T_PTROBJ Net::LDNS::RR::MINFO T_PTROBJ Net::LDNS::RR::MR T_PTROBJ Net::LDNS::RR::MX T_PTROBJ Net::LDNS::RR::NAPTR T_PTROBJ Net::LDNS::RR::NID T_PTROBJ Net::LDNS::RR::NIMLOC T_PTROBJ Net::LDNS::RR::NINFO T_PTROBJ Net::LDNS::RR::NS T_PTROBJ Net::LDNS::RR::NSAP T_PTROBJ Net::LDNS::RR::NSEC T_PTROBJ Net::LDNS::RR::NSEC3 T_PTROBJ Net::LDNS::RR::NSEC3PARAM T_PTROBJ Net::LDNS::RR::NULL T_PTROBJ Net::LDNS::RR::NXT T_PTROBJ Net::LDNS::RR::PTR T_PTROBJ Net::LDNS::RR::PX T_PTROBJ Net::LDNS::RR::RKEY T_PTROBJ Net::LDNS::RR::RP T_PTROBJ Net::LDNS::RR::RRSIG T_PTROBJ Net::LDNS::RR::RT T_PTROBJ Net::LDNS::RR::SIG T_PTROBJ Net::LDNS::RR::SINK T_PTROBJ Net::LDNS::RR::SOA T_PTROBJ Net::LDNS::RR::SPF T_PTROBJ Net::LDNS::RR::SRV T_PTROBJ Net::LDNS::RR::SSHFP T_PTROBJ Net::LDNS::RR::TA T_PTROBJ Net::LDNS::RR::TALINK T_PTROBJ Net::LDNS::RR::TKEY T_PTROBJ Net::LDNS::RR::TLSA T_PTROBJ Net::LDNS::RR::TXT T_PTROBJ Net::LDNS::RR::TYPE T_PTROBJ Net::LDNS::RR::UID T_PTROBJ Net::LDNS::RR::UINFO T_PTROBJ Net::LDNS::RR::UNSPEC T_PTROBJ Net::LDNS::RR::URI T_PTROBJ Net::LDNS::RR::WKS T_PTROBJ Net::LDNS::RR::X25 T_PTROBJ Net-LDNS-0.75/src/ldns/buffer.c000644 000770 000024 00000007351 12471046240 016466 0ustar00calledstaff000000 000000 /* * buffer.c -- generic memory buffer . * * Copyright (c) 2001-2008, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include #include #include ldns_buffer * ldns_buffer_new(size_t capacity) { ldns_buffer *buffer = LDNS_MALLOC(ldns_buffer); if (!buffer) { return NULL; } buffer->_data = (uint8_t *) LDNS_XMALLOC(uint8_t, capacity); if (!buffer->_data) { LDNS_FREE(buffer); return NULL; } buffer->_position = 0; buffer->_limit = buffer->_capacity = capacity; buffer->_fixed = 0; buffer->_status = LDNS_STATUS_OK; ldns_buffer_invariant(buffer); return buffer; } void ldns_buffer_new_frm_data(ldns_buffer *buffer, void *data, size_t size) { assert(data != NULL); buffer->_position = 0; buffer->_limit = buffer->_capacity = size; buffer->_fixed = 0; buffer->_data = LDNS_XMALLOC(uint8_t, size); if(!buffer->_data) { buffer->_status = LDNS_STATUS_MEM_ERR; return; } memcpy(buffer->_data, data, size); buffer->_status = LDNS_STATUS_OK; ldns_buffer_invariant(buffer); } bool ldns_buffer_set_capacity(ldns_buffer *buffer, size_t capacity) { void *data; ldns_buffer_invariant(buffer); assert(buffer->_position <= capacity); data = (uint8_t *) LDNS_XREALLOC(buffer->_data, uint8_t, capacity); if (!data) { buffer->_status = LDNS_STATUS_MEM_ERR; return false; } else { buffer->_data = data; buffer->_limit = buffer->_capacity = capacity; return true; } } bool ldns_buffer_reserve(ldns_buffer *buffer, size_t amount) { ldns_buffer_invariant(buffer); assert(!buffer->_fixed); if (buffer->_capacity < buffer->_position + amount) { size_t new_capacity = buffer->_capacity * 3 / 2; if (new_capacity < buffer->_position + amount) { new_capacity = buffer->_position + amount; } if (!ldns_buffer_set_capacity(buffer, new_capacity)) { buffer->_status = LDNS_STATUS_MEM_ERR; return false; } } buffer->_limit = buffer->_capacity; return true; } int ldns_buffer_printf(ldns_buffer *buffer, const char *format, ...) { va_list args; int written = 0; size_t remaining; if (ldns_buffer_status_ok(buffer)) { ldns_buffer_invariant(buffer); assert(buffer->_limit == buffer->_capacity); remaining = ldns_buffer_remaining(buffer); va_start(args, format); written = vsnprintf((char *) ldns_buffer_current(buffer), remaining, format, args); va_end(args); if (written == -1) { buffer->_status = LDNS_STATUS_INTERNAL_ERR; return -1; } else if ((size_t) written >= remaining) { if (!ldns_buffer_reserve(buffer, (size_t) written + 1)) { buffer->_status = LDNS_STATUS_MEM_ERR; return -1; } va_start(args, format); written = vsnprintf((char *) ldns_buffer_current(buffer), ldns_buffer_remaining(buffer), format, args); va_end(args); if (written == -1) { buffer->_status = LDNS_STATUS_INTERNAL_ERR; return -1; } } buffer->_position += written; } return written; } void ldns_buffer_free(ldns_buffer *buffer) { if (!buffer) { return; } if (!buffer->_fixed) LDNS_FREE(buffer->_data); LDNS_FREE(buffer); } void * ldns_buffer_export(ldns_buffer *buffer) { buffer->_fixed = 1; return buffer->_data; } int ldns_bgetc(ldns_buffer *buffer) { if (!ldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) { ldns_buffer_set_position(buffer, ldns_buffer_limit(buffer)); /* ldns_buffer_rewind(buffer);*/ return EOF; } return (int)ldns_buffer_read_u8(buffer); } void ldns_buffer_copy(ldns_buffer* result, ldns_buffer* from) { size_t tocopy = ldns_buffer_limit(from); if(tocopy > ldns_buffer_capacity(result)) tocopy = ldns_buffer_capacity(result); ldns_buffer_clear(result); ldns_buffer_write(result, ldns_buffer_begin(from), tocopy); ldns_buffer_flip(result); } Net-LDNS-0.75/src/ldns/compat/000755 000770 000024 00000000000 12510741546 016333 5ustar00calledstaff000000 000000 Net-LDNS-0.75/src/ldns/dane.c000644 000770 000024 00000041755 12471046240 016132 0ustar00calledstaff000000 000000 /* * Verify or create TLS authentication with DANE (RFC6698) * * (c) NLnetLabs 2012 * * See the file LICENSE for the license. * */ #include #ifdef USE_DANE #include #include #include #include #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_SSL #include #include #include #endif ldns_status ldns_dane_create_tlsa_owner(ldns_rdf** tlsa_owner, const ldns_rdf* name, uint16_t port, ldns_dane_transport transport) { char buf[LDNS_MAX_DOMAINLEN]; size_t s; assert(tlsa_owner != NULL); assert(name != NULL); assert(ldns_rdf_get_type(name) == LDNS_RDF_TYPE_DNAME); s = (size_t)snprintf(buf, LDNS_MAX_DOMAINLEN, "X_%d", (int)port); buf[0] = (char)(s - 1); switch(transport) { case LDNS_DANE_TRANSPORT_TCP: s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\004_tcp"); break; case LDNS_DANE_TRANSPORT_UDP: s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\004_udp"); break; case LDNS_DANE_TRANSPORT_SCTP: s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\005_sctp"); break; default: return LDNS_STATUS_DANE_UNKNOWN_TRANSPORT; } if (s + ldns_rdf_size(name) > LDNS_MAX_DOMAINLEN) { return LDNS_STATUS_DOMAINNAME_OVERFLOW; } memcpy(buf + s, ldns_rdf_data(name), ldns_rdf_size(name)); *tlsa_owner = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, s + ldns_rdf_size(name), buf); if (*tlsa_owner == NULL) { return LDNS_STATUS_MEM_ERR; } return LDNS_STATUS_OK; } #ifdef HAVE_SSL ldns_status ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert, ldns_tlsa_selector selector, ldns_tlsa_matching_type matching_type) { unsigned char* buf = NULL; size_t len; X509_PUBKEY* xpubkey; EVP_PKEY* epubkey; unsigned char* digest; assert(rdf != NULL); assert(cert != NULL); switch(selector) { case LDNS_TLSA_SELECTOR_FULL_CERTIFICATE: len = (size_t)i2d_X509(cert, &buf); break; case LDNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO: #ifndef S_SPLINT_S xpubkey = X509_get_X509_PUBKEY(cert); #endif if (! xpubkey) { return LDNS_STATUS_SSL_ERR; } epubkey = X509_PUBKEY_get(xpubkey); if (! epubkey) { return LDNS_STATUS_SSL_ERR; } len = (size_t)i2d_PUBKEY(epubkey, &buf); break; default: return LDNS_STATUS_DANE_UNKNOWN_SELECTOR; } switch(matching_type) { case LDNS_TLSA_MATCHING_TYPE_NO_HASH_USED: *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, len, buf); return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; break; case LDNS_TLSA_MATCHING_TYPE_SHA256: digest = LDNS_XMALLOC(unsigned char, LDNS_SHA256_DIGEST_LENGTH); if (digest == NULL) { LDNS_FREE(buf); return LDNS_STATUS_MEM_ERR; } (void) ldns_sha256(buf, (unsigned int)len, digest); *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, LDNS_SHA256_DIGEST_LENGTH, digest); LDNS_FREE(buf); return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; break; case LDNS_TLSA_MATCHING_TYPE_SHA512: digest = LDNS_XMALLOC(unsigned char, LDNS_SHA512_DIGEST_LENGTH); if (digest == NULL) { LDNS_FREE(buf); return LDNS_STATUS_MEM_ERR; } (void) ldns_sha512(buf, (unsigned int)len, digest); *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, LDNS_SHA512_DIGEST_LENGTH, digest); LDNS_FREE(buf); return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; break; default: LDNS_FREE(buf); return LDNS_STATUS_DANE_UNKNOWN_MATCHING_TYPE; } } /* Ordinary PKIX validation of cert (with extra_certs to help) * against the CA's in store */ static ldns_status ldns_dane_pkix_validate(X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* store) { X509_STORE_CTX* vrfy_ctx; ldns_status s; if (! store) { return LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE; } vrfy_ctx = X509_STORE_CTX_new(); if (! vrfy_ctx) { return LDNS_STATUS_SSL_ERR; } else if (X509_STORE_CTX_init(vrfy_ctx, store, cert, extra_certs) != 1) { s = LDNS_STATUS_SSL_ERR; } else if (X509_verify_cert(vrfy_ctx) == 1) { s = LDNS_STATUS_OK; } else { s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE; } X509_STORE_CTX_free(vrfy_ctx); return s; } /* Orinary PKIX validation of cert (with extra_certs to help) * against the CA's in store, but also return the validation chain. */ static ldns_status ldns_dane_pkix_validate_and_get_chain(STACK_OF(X509)** chain, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* store) { ldns_status s; X509_STORE* empty_store = NULL; X509_STORE_CTX* vrfy_ctx; assert(chain != NULL); if (! store) { store = empty_store = X509_STORE_new(); } s = LDNS_STATUS_SSL_ERR; vrfy_ctx = X509_STORE_CTX_new(); if (! vrfy_ctx) { goto exit_free_empty_store; } else if (X509_STORE_CTX_init(vrfy_ctx, store, cert, extra_certs) != 1) { goto exit_free_vrfy_ctx; } else if (X509_verify_cert(vrfy_ctx) == 1) { s = LDNS_STATUS_OK; } else { s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE; } *chain = X509_STORE_CTX_get1_chain(vrfy_ctx); if (! *chain) { s = LDNS_STATUS_SSL_ERR; } exit_free_vrfy_ctx: X509_STORE_CTX_free(vrfy_ctx); exit_free_empty_store: if (empty_store) { X509_STORE_free(empty_store); } return s; } /* Return the validation chain that can be build out of cert, with extra_certs. */ static ldns_status ldns_dane_pkix_get_chain(STACK_OF(X509)** chain, X509* cert, STACK_OF(X509)* extra_certs) { ldns_status s; X509_STORE* empty_store = NULL; X509_STORE_CTX* vrfy_ctx; assert(chain != NULL); empty_store = X509_STORE_new(); s = LDNS_STATUS_SSL_ERR; vrfy_ctx = X509_STORE_CTX_new(); if (! vrfy_ctx) { goto exit_free_empty_store; } else if (X509_STORE_CTX_init(vrfy_ctx, empty_store, cert, extra_certs) != 1) { goto exit_free_vrfy_ctx; } (void) X509_verify_cert(vrfy_ctx); *chain = X509_STORE_CTX_get1_chain(vrfy_ctx); if (! *chain) { s = LDNS_STATUS_SSL_ERR; } else { s = LDNS_STATUS_OK; } exit_free_vrfy_ctx: X509_STORE_CTX_free(vrfy_ctx); exit_free_empty_store: X509_STORE_free(empty_store); return s; } /* Pop n+1 certs and return the last popped. */ static ldns_status ldns_dane_get_nth_cert_from_validation_chain( X509** cert, STACK_OF(X509)* chain, int n, bool ca) { if (n >= sk_X509_num(chain) || n < 0) { return LDNS_STATUS_DANE_OFFSET_OUT_OF_RANGE; } *cert = sk_X509_pop(chain); while (n-- > 0) { X509_free(*cert); *cert = sk_X509_pop(chain); } if (ca && ! X509_check_ca(*cert)) { return LDNS_STATUS_DANE_NON_CA_CERTIFICATE; } return LDNS_STATUS_OK; } /* Create validation chain with cert and extra_certs and returns the last * self-signed (if present). */ static ldns_status ldns_dane_pkix_get_last_self_signed(X509** out_cert, X509* cert, STACK_OF(X509)* extra_certs) { ldns_status s; X509_STORE* empty_store = NULL; X509_STORE_CTX* vrfy_ctx; assert(out_cert != NULL); empty_store = X509_STORE_new(); s = LDNS_STATUS_SSL_ERR; vrfy_ctx = X509_STORE_CTX_new(); if (! vrfy_ctx) { goto exit_free_empty_store; } else if (X509_STORE_CTX_init(vrfy_ctx, empty_store, cert, extra_certs) != 1) { goto exit_free_vrfy_ctx; } (void) X509_verify_cert(vrfy_ctx); if (vrfy_ctx->error == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN || vrfy_ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT){ *out_cert = X509_STORE_CTX_get_current_cert( vrfy_ctx); s = LDNS_STATUS_OK; } else { s = LDNS_STATUS_DANE_PKIX_NO_SELF_SIGNED_TRUST_ANCHOR; } exit_free_vrfy_ctx: X509_STORE_CTX_free(vrfy_ctx); exit_free_empty_store: X509_STORE_free(empty_store); return s; } ldns_status ldns_dane_select_certificate(X509** selected_cert, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* pkix_validation_store, ldns_tlsa_certificate_usage cert_usage, int offset) { ldns_status s; STACK_OF(X509)* pkix_validation_chain = NULL; assert(selected_cert != NULL); assert(cert != NULL); /* With PKIX validation explicitely turned off (pkix_validation_store * == NULL), treat the "CA constraint" and "Service certificate * constraint" the same as "Trust anchor assertion" and "Domain issued * certificate" respectively. */ if (pkix_validation_store == NULL) { switch (cert_usage) { case LDNS_TLSA_USAGE_CA_CONSTRAINT: cert_usage = LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION; break; case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT: cert_usage = LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE; break; default: break; } } /* Now what to do with each Certificate usage... */ switch (cert_usage) { case LDNS_TLSA_USAGE_CA_CONSTRAINT: s = ldns_dane_pkix_validate_and_get_chain( &pkix_validation_chain, cert, extra_certs, pkix_validation_store); if (! pkix_validation_chain) { return s; } if (s == LDNS_STATUS_OK) { if (offset == -1) { offset = 0; } s = ldns_dane_get_nth_cert_from_validation_chain( selected_cert, pkix_validation_chain, offset, true); } sk_X509_pop_free(pkix_validation_chain, X509_free); return s; break; case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT: *selected_cert = cert; return ldns_dane_pkix_validate(cert, extra_certs, pkix_validation_store); break; case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION: if (offset == -1) { s = ldns_dane_pkix_get_last_self_signed( selected_cert, cert, extra_certs); return s; } else { s = ldns_dane_pkix_get_chain( &pkix_validation_chain, cert, extra_certs); if (s == LDNS_STATUS_OK) { s = ldns_dane_get_nth_cert_from_validation_chain( selected_cert, pkix_validation_chain, offset, false); } else if (! pkix_validation_chain) { return s; } sk_X509_pop_free(pkix_validation_chain, X509_free); return s; } break; case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE: *selected_cert = cert; return LDNS_STATUS_OK; break; default: return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE; break; } } ldns_status ldns_dane_create_tlsa_rr(ldns_rr** tlsa, ldns_tlsa_certificate_usage certificate_usage, ldns_tlsa_selector selector, ldns_tlsa_matching_type matching_type, X509* cert) { ldns_rdf* rdf; ldns_status s; assert(tlsa != NULL); assert(cert != NULL); /* create rr */ *tlsa = ldns_rr_new_frm_type(LDNS_RR_TYPE_TLSA); if (*tlsa == NULL) { return LDNS_STATUS_MEM_ERR; } rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)certificate_usage); if (rdf == NULL) { goto memerror; } (void) ldns_rr_set_rdf(*tlsa, rdf, 0); rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)selector); if (rdf == NULL) { goto memerror; } (void) ldns_rr_set_rdf(*tlsa, rdf, 1); rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)matching_type); if (rdf == NULL) { goto memerror; } (void) ldns_rr_set_rdf(*tlsa, rdf, 2); s = ldns_dane_cert2rdf(&rdf, cert, selector, matching_type); if (s == LDNS_STATUS_OK) { (void) ldns_rr_set_rdf(*tlsa, rdf, 3); return LDNS_STATUS_OK; } ldns_rr_free(*tlsa); *tlsa = NULL; return s; memerror: ldns_rr_free(*tlsa); *tlsa = NULL; return LDNS_STATUS_MEM_ERR; } /* Return tlsas that actually are TLSA resource records with known values * for the Certificate usage, Selector and Matching type rdata fields. */ static ldns_rr_list* ldns_dane_filter_unusable_records(const ldns_rr_list* tlsas) { size_t i; ldns_rr_list* r = ldns_rr_list_new(); ldns_rr* tlsa_rr; if (! r) { return NULL; } for (i = 0; i < ldns_rr_list_rr_count(tlsas); i++) { tlsa_rr = ldns_rr_list_rr(tlsas, i); if (ldns_rr_get_type(tlsa_rr) == LDNS_RR_TYPE_TLSA && ldns_rr_rd_count(tlsa_rr) == 4 && ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0)) <= 3 && ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1)) <= 1 && ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2)) <= 2) { if (! ldns_rr_list_push_rr(r, tlsa_rr)) { ldns_rr_list_free(r); return NULL; } } } return r; } /* Return whether cert/selector/matching_type matches data. */ static ldns_status ldns_dane_match_cert_with_data(X509* cert, ldns_tlsa_selector selector, ldns_tlsa_matching_type matching_type, ldns_rdf* data) { ldns_status s; ldns_rdf* match_data; s = ldns_dane_cert2rdf(&match_data, cert, selector, matching_type); if (s == LDNS_STATUS_OK) { if (ldns_rdf_compare(data, match_data) != 0) { s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH; } ldns_rdf_free(match_data); } return s; } /* Return whether any certificate from the chain with selector/matching_type * matches data. * ca should be true if the certificate has to be a CA certificate too. */ static ldns_status ldns_dane_match_any_cert_with_data(STACK_OF(X509)* chain, ldns_tlsa_selector selector, ldns_tlsa_matching_type matching_type, ldns_rdf* data, bool ca) { ldns_status s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH; size_t n, i; X509* cert; n = (size_t)sk_X509_num(chain); for (i = 0; i < n; i++) { cert = sk_X509_pop(chain); if (! cert) { s = LDNS_STATUS_SSL_ERR; break; } s = ldns_dane_match_cert_with_data(cert, selector, matching_type, data); if (ca && s == LDNS_STATUS_OK && ! X509_check_ca(cert)) { s = LDNS_STATUS_DANE_NON_CA_CERTIFICATE; } X509_free(cert); if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH) { break; } /* when s == LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH, * try to match the next certificate */ } return s; } ldns_status ldns_dane_verify_rr(const ldns_rr* tlsa_rr, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* pkix_validation_store) { ldns_status s; STACK_OF(X509)* pkix_validation_chain = NULL; ldns_tlsa_certificate_usage cert_usage; ldns_tlsa_selector selector; ldns_tlsa_matching_type matching_type; ldns_rdf* data; if (! tlsa_rr) { /* No TLSA, so regular PKIX validation */ return ldns_dane_pkix_validate(cert, extra_certs, pkix_validation_store); } cert_usage = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0)); selector = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1)); matching_type = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2)); data = ldns_rr_rdf(tlsa_rr, 3) ; switch (cert_usage) { case LDNS_TLSA_USAGE_CA_CONSTRAINT: s = ldns_dane_pkix_validate_and_get_chain( &pkix_validation_chain, cert, extra_certs, pkix_validation_store); if (! pkix_validation_chain) { return s; } if (s == LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE) { /* * NO PKIX validation. We still try to match *any* * certificate from the chain, so we return * TLSA errors over PKIX errors. * * i.e. When the TLSA matches no certificate, we return * TLSA_DID_NOT_MATCH and not PKIX_DID_NOT_VALIDATE */ s = ldns_dane_match_any_cert_with_data( pkix_validation_chain, selector, matching_type, data, true); if (s == LDNS_STATUS_OK) { /* A TLSA record did match a cert from the * chain, thus the error is failed PKIX * validation. */ s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE; } } else if (s == LDNS_STATUS_OK) { /* PKIX validated, does the TLSA match too? */ s = ldns_dane_match_any_cert_with_data( pkix_validation_chain, selector, matching_type, data, true); } sk_X509_pop_free(pkix_validation_chain, X509_free); return s; break; case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT: s = ldns_dane_match_cert_with_data(cert, selector, matching_type, data); if (s == LDNS_STATUS_OK) { return ldns_dane_pkix_validate(cert, extra_certs, pkix_validation_store); } return s; break; case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION: s = ldns_dane_pkix_get_chain(&pkix_validation_chain, cert, extra_certs); if (s == LDNS_STATUS_OK) { s = ldns_dane_match_any_cert_with_data( pkix_validation_chain, selector, matching_type, data, false); } else if (! pkix_validation_chain) { return s; } sk_X509_pop_free(pkix_validation_chain, X509_free); return s; break; case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE: return ldns_dane_match_cert_with_data(cert, selector, matching_type, data); break; default: break; } return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE; } ldns_status ldns_dane_verify(ldns_rr_list* tlsas, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* pkix_validation_store) { size_t i; ldns_rr* tlsa_rr; ldns_status s = LDNS_STATUS_OK, ps; assert(cert != NULL); if (tlsas && ldns_rr_list_rr_count(tlsas) > 0) { tlsas = ldns_dane_filter_unusable_records(tlsas); if (! tlsas) { return LDNS_STATUS_MEM_ERR; } } if (! tlsas || ldns_rr_list_rr_count(tlsas) == 0) { /* No TLSA's, so regular PKIX validation */ return ldns_dane_pkix_validate(cert, extra_certs, pkix_validation_store); } else { for (i = 0; i < ldns_rr_list_rr_count(tlsas); i++) { tlsa_rr = ldns_rr_list_rr(tlsas, i); ps = s; s = ldns_dane_verify_rr(tlsa_rr, cert, extra_certs, pkix_validation_store); if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH && s != LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE) { /* which would be LDNS_STATUS_OK (match) * or some fatal error preventing use from * trying the next TLSA record. */ break; } s = (s > ps ? s : ps); /* prefer PKIX_DID_NOT_VALIDATE * over TLSA_DID_NOT_MATCH */ } ldns_rr_list_free(tlsas); } return s; } #endif /* HAVE_SSL */ #endif /* USE_DANE */ Net-LDNS-0.75/src/ldns/dname.c000644 000770 000024 00000032022 12471046240 016272 0ustar00calledstaff000000 000000 /* * dname.c * * dname specific rdata implementations * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME * It is not a /real/ type! All function must therefor check * for LDNS_RDF_TYPE_DNAME. * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif /* Returns whether the last label in the name is a root label (a empty label). * Note that it is not enough to just test the last character to be 0, * because it may be part of the last label itself. */ static bool ldns_dname_last_label_is_root_label(const ldns_rdf* dname) { size_t src_pos; size_t len = 0; for (src_pos = 0; src_pos < ldns_rdf_size(dname); src_pos += len + 1) { len = ldns_rdf_data(dname)[src_pos]; } assert(src_pos == ldns_rdf_size(dname)); return src_pos > 0 && len == 0; } ldns_rdf * ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2) { ldns_rdf *new; uint16_t new_size; uint8_t *buf; uint16_t left_size; if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME || ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) { return NULL; } /* remove root label if it is present at the end of the left * rd, by reducing the size with 1 */ left_size = ldns_rdf_size(rd1); if (ldns_dname_last_label_is_root_label(rd1)) { left_size--; } /* we overwrite the nullbyte of rd1 */ new_size = left_size + ldns_rdf_size(rd2); buf = LDNS_XMALLOC(uint8_t, new_size); if (!buf) { return NULL; } /* put the two dname's after each other */ memcpy(buf, ldns_rdf_data(rd1), left_size); memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2)); new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf); LDNS_FREE(buf); return new; } ldns_status ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2) { uint16_t left_size; uint16_t size; uint8_t* newd; if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME || ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) { return LDNS_STATUS_ERR; } /* remove root label if it is present at the end of the left * rd, by reducing the size with 1 */ left_size = ldns_rdf_size(rd1); if (ldns_dname_last_label_is_root_label(rd1)) { left_size--; } size = left_size + ldns_rdf_size(rd2); newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size); if(!newd) { return LDNS_STATUS_MEM_ERR; } ldns_rdf_set_data(rd1, newd); memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2)); ldns_rdf_set_size(rd1, size); return LDNS_STATUS_OK; } ldns_rdf* ldns_dname_reverse(const ldns_rdf *dname) { size_t rd_size; uint8_t* buf; ldns_rdf* new; size_t src_pos; size_t len ; assert(ldns_rdf_get_type(dname) == LDNS_RDF_TYPE_DNAME); rd_size = ldns_rdf_size(dname); buf = LDNS_XMALLOC(uint8_t, rd_size); if (! buf) { return NULL; } new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf); if (! new) { LDNS_FREE(buf); return NULL; } /* If dname ends in a root label, the reverse should too. */ if (ldns_dname_last_label_is_root_label(dname)) { buf[rd_size - 1] = 0; rd_size -= 1; } for (src_pos = 0; src_pos < rd_size; src_pos += len + 1) { len = ldns_rdf_data(dname)[src_pos]; memcpy(&buf[rd_size - src_pos - len - 1], &ldns_rdf_data(dname)[src_pos], len + 1); } return new; } ldns_rdf * ldns_dname_clone_from(const ldns_rdf *d, uint16_t n) { uint8_t *data; uint8_t label_size; size_t data_size; if (!d || ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME || ldns_dname_label_count(d) < n) { return NULL; } data = ldns_rdf_data(d); data_size = ldns_rdf_size(d); while (n > 0) { label_size = data[0] + 1; data += label_size; if (data_size < label_size) { /* this label is very broken */ return NULL; } data_size -= label_size; n--; } return ldns_dname_new_frm_data(data_size, data); } ldns_rdf * ldns_dname_left_chop(const ldns_rdf *d) { uint8_t label_pos; ldns_rdf *chop; if (!d) { return NULL; } if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) { return NULL; } if (ldns_dname_label_count(d) == 0) { /* root label */ return NULL; } /* 05blaat02nl00 */ label_pos = ldns_rdf_data(d)[0]; chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1, ldns_rdf_data(d) + label_pos + 1); return chop; } uint8_t ldns_dname_label_count(const ldns_rdf *r) { uint16_t src_pos; uint16_t len; uint8_t i; size_t r_size; if (!r) { return 0; } i = 0; src_pos = 0; r_size = ldns_rdf_size(r); if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) { return 0; } else { len = ldns_rdf_data(r)[src_pos]; /* start of the label */ /* single root label */ if (1 == r_size) { return 0; } else { while ((len > 0) && src_pos < r_size) { src_pos++; src_pos += len; len = ldns_rdf_data(r)[src_pos]; i++; } } } return i; } ldns_rdf * ldns_dname_new(uint16_t s, void *d) { ldns_rdf *rd; rd = LDNS_MALLOC(ldns_rdf); if (!rd) { return NULL; } ldns_rdf_set_size(rd, s); ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME); ldns_rdf_set_data(rd, d); return rd; } ldns_rdf * ldns_dname_new_frm_str(const char *str) { return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str); } ldns_rdf * ldns_dname_new_frm_data(uint16_t size, const void *data) { return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data); } void ldns_dname2canonical(const ldns_rdf *rd) { uint8_t *rdd; uint16_t i; if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) { return; } rdd = (uint8_t*)ldns_rdf_data(rd); for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) { *rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd); } } bool ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent) { uint8_t sub_lab; uint8_t par_lab; int8_t i, j; ldns_rdf *tmp_sub = NULL; ldns_rdf *tmp_par = NULL; ldns_rdf *sub_clone; ldns_rdf *parent_clone; bool result = true; if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME || ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME || ldns_rdf_compare(sub, parent) == 0) { return false; } /* would be nicer if we do not have to clone... */ sub_clone = ldns_dname_clone_from(sub, 0); parent_clone = ldns_dname_clone_from(parent, 0); ldns_dname2canonical(sub_clone); ldns_dname2canonical(parent_clone); sub_lab = ldns_dname_label_count(sub_clone); par_lab = ldns_dname_label_count(parent_clone); /* if sub sits above parent, it cannot be a child/sub domain */ if (sub_lab < par_lab) { result = false; } else { /* check all labels the from the parent labels, from right to left. * When they /all/ match we have found a subdomain */ j = sub_lab - 1; /* we count from zero, thank you */ for (i = par_lab -1; i >= 0; i--) { tmp_sub = ldns_dname_label(sub_clone, j); tmp_par = ldns_dname_label(parent_clone, i); if (!tmp_sub || !tmp_par) { /* deep free does null check */ ldns_rdf_deep_free(tmp_sub); ldns_rdf_deep_free(tmp_par); result = false; break; } if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) { /* they are not equal */ ldns_rdf_deep_free(tmp_sub); ldns_rdf_deep_free(tmp_par); result = false; break; } ldns_rdf_deep_free(tmp_sub); ldns_rdf_deep_free(tmp_par); j--; } } ldns_rdf_deep_free(sub_clone); ldns_rdf_deep_free(parent_clone); return result; } int ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2) { size_t lc1, lc2, lc1f, lc2f; size_t i; int result = 0; uint8_t *lp1, *lp2; /* see RFC4034 for this algorithm */ /* this algorithm assumes the names are normalized to case */ /* only when both are not NULL we can say anything about them */ if (!dname1 && !dname2) { return 0; } if (!dname1 || !dname2) { return -1; } /* asserts must happen later as we are looking in the * dname, which could be NULL. But this case is handled * above */ assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME); assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME); lc1 = ldns_dname_label_count(dname1); lc2 = ldns_dname_label_count(dname2); if (lc1 == 0 && lc2 == 0) { return 0; } if (lc1 == 0) { return -1; } if (lc2 == 0) { return 1; } lc1--; lc2--; /* we start at the last label */ while (true) { /* find the label first */ lc1f = lc1; lp1 = ldns_rdf_data(dname1); while (lc1f > 0) { lp1 += *lp1 + 1; lc1f--; } /* and find the other one */ lc2f = lc2; lp2 = ldns_rdf_data(dname2); while (lc2f > 0) { lp2 += *lp2 + 1; lc2f--; } /* now check the label character for character. */ for (i = 1; i < (size_t)(*lp1 + 1); i++) { if (i > *lp2) { /* apparently label 1 is larger */ result = 1; goto done; } if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) < LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) { result = -1; goto done; } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) > LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) { result = 1; goto done; } } if (*lp1 < *lp2) { /* apparently label 2 is larger */ result = -1; goto done; } if (lc1 == 0 && lc2 > 0) { result = -1; goto done; } else if (lc1 > 0 && lc2 == 0) { result = 1; goto done; } else if (lc1 == 0 && lc2 == 0) { result = 0; goto done; } lc1--; lc2--; } done: return result; } int ldns_dname_is_wildcard(const ldns_rdf* dname) { return ( ldns_dname_label_count(dname) > 0 && ldns_rdf_data(dname)[0] == 1 && ldns_rdf_data(dname)[1] == '*'); } int ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard) { ldns_rdf *wc_chopped; int result; /* check whether it really is a wildcard */ if (ldns_dname_is_wildcard(wildcard)) { /* ok, so the dname needs to be a subdomain of the wildcard * without the * */ wc_chopped = ldns_dname_left_chop(wildcard); result = (int) ldns_dname_is_subdomain(dname, wc_chopped); ldns_rdf_deep_free(wc_chopped); } else { result = (ldns_dname_compare(dname, wildcard) == 0); } return result; } /* nsec test: does prev <= middle < next * -1 = yes * 0 = error/can't tell * 1 = no */ int ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle, const ldns_rdf *next) { int prev_check, next_check; assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME); assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME); assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME); prev_check = ldns_dname_compare(prev, middle); next_check = ldns_dname_compare(middle, next); /* <= next. This cannot be the case for nsec, because then we would * have gotten the nsec of next... */ if (next_check == 0) { return 0; } /* <= */ if ((prev_check == -1 || prev_check == 0) && /* < */ next_check == -1) { return -1; } else { return 1; } } bool ldns_dname_str_absolute(const char *dname_str) { const char* s; if(dname_str && strcmp(dname_str, ".") == 0) return 1; if(!dname_str || strlen(dname_str) < 2) return 0; if(dname_str[strlen(dname_str) - 1] != '.') return 0; if(dname_str[strlen(dname_str) - 2] != '\\') return 1; /* ends in . and no \ before it */ /* so we have the case of ends in . and there is \ before it */ for(s=dname_str; *s; s++) { if(*s == '\\') { if(s[1] && s[2] && s[3] /* check length */ && isdigit(s[1]) && isdigit(s[2]) && isdigit(s[3])) s += 3; else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */ return 0; /* parse error */ else s++; /* another character escaped */ } else if(!*(s+1) && *s == '.') return 1; /* trailing dot, unescaped */ } return 0; } bool ldns_dname_absolute(const ldns_rdf *rdf) { char *str = ldns_rdf2str(rdf); if (str) { bool r = ldns_dname_str_absolute(str); LDNS_FREE(str); return r; } return false; } ldns_rdf * ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos) { uint8_t labelcnt; uint16_t src_pos; uint16_t len; ldns_rdf *tmpnew; size_t s; uint8_t *data; if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) { return NULL; } labelcnt = 0; src_pos = 0; s = ldns_rdf_size(rdf); len = ldns_rdf_data(rdf)[src_pos]; /* label start */ while ((len > 0) && src_pos < s) { if (labelcnt == labelpos) { /* found our label */ data = LDNS_XMALLOC(uint8_t, len + 2); if (!data) { return NULL; } memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1); data[len + 2 - 1] = 0; tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME , len + 2, data); if (!tmpnew) { LDNS_FREE(data); return NULL; } return tmpnew; } src_pos++; src_pos += len; len = ldns_rdf_data(rdf)[src_pos]; labelcnt++; } return NULL; } Net-LDNS-0.75/src/ldns/dnssec.c000644 000770 000024 00000134230 12471046240 016471 0ustar00calledstaff000000 000000 /* * dnssec.c * * contains the cryptographic function needed for DNSSEC in ldns * The crypto library used is openssl * * (c) NLnet Labs, 2004-2008 * * See the file LICENSE for the license */ #include #include #include #include #include #ifdef HAVE_SSL #include #include #include #include #include #endif ldns_rr * ldns_dnssec_get_rrsig_for_name_and_type(const ldns_rdf *name, const ldns_rr_type type, const ldns_rr_list *rrs) { size_t i; ldns_rr *candidate; if (!name || !rrs) { return NULL; } for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) { candidate = ldns_rr_list_rr(rrs, i); if (ldns_rr_get_type(candidate) == LDNS_RR_TYPE_RRSIG) { if (ldns_dname_compare(ldns_rr_owner(candidate), name) == 0 && ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(candidate)) == type ) { return candidate; } } } return NULL; } ldns_rr * ldns_dnssec_get_dnskey_for_rrsig(const ldns_rr *rrsig, const ldns_rr_list *rrs) { size_t i; ldns_rr *candidate; if (!rrsig || !rrs) { return NULL; } for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) { candidate = ldns_rr_list_rr(rrs, i); if (ldns_rr_get_type(candidate) == LDNS_RR_TYPE_DNSKEY) { if (ldns_dname_compare(ldns_rr_owner(candidate), ldns_rr_rrsig_signame(rrsig)) == 0 && ldns_rdf2native_int16(ldns_rr_rrsig_keytag(rrsig)) == ldns_calc_keytag(candidate) ) { return candidate; } } } return NULL; } ldns_rdf * ldns_nsec_get_bitmap(ldns_rr *nsec) { if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC) { return ldns_rr_rdf(nsec, 1); } else if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC3) { return ldns_rr_rdf(nsec, 5); } else { return NULL; } } /*return the owner name of the closest encloser for name from the list of rrs */ /* this is NOT the hash, but the original name! */ ldns_rdf * ldns_dnssec_nsec3_closest_encloser(ldns_rdf *qname, ATTR_UNUSED(ldns_rr_type qtype), ldns_rr_list *nsec3s) { /* remember parameters, they must match */ uint8_t algorithm; uint32_t iterations; uint8_t salt_length; uint8_t *salt; ldns_rdf *sname, *hashed_sname, *tmp; bool flag; bool exact_match_found; bool in_range_found; ldns_status status; ldns_rdf *zone_name; size_t nsec_i; ldns_rr *nsec; ldns_rdf *result = NULL; if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) { return NULL; } nsec = ldns_rr_list_rr(nsec3s, 0); algorithm = ldns_nsec3_algorithm(nsec); salt_length = ldns_nsec3_salt_length(nsec); salt = ldns_nsec3_salt_data(nsec); iterations = ldns_nsec3_iterations(nsec); sname = ldns_rdf_clone(qname); flag = false; zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec)); /* algorithm from nsec3-07 8.3 */ while (ldns_dname_label_count(sname) > 0) { exact_match_found = false; in_range_found = false; hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt); status = ldns_dname_cat(hashed_sname, zone_name); if(status != LDNS_STATUS_OK) { LDNS_FREE(salt); ldns_rdf_deep_free(zone_name); ldns_rdf_deep_free(sname); return NULL; } for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) { nsec = ldns_rr_list_rr(nsec3s, nsec_i); /* check values of iterations etc! */ /* exact match? */ if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) { exact_match_found = true; } else if (ldns_nsec_covers_name(nsec, hashed_sname)) { in_range_found = true; } } if (!exact_match_found && in_range_found) { flag = true; } else if (exact_match_found && flag) { result = ldns_rdf_clone(sname); /* RFC 5155: 8.3. 2.** "The proof is complete" */ ldns_rdf_deep_free(hashed_sname); goto done; } else if (exact_match_found && !flag) { /* error! */ ldns_rdf_deep_free(hashed_sname); goto done; } else { flag = false; } ldns_rdf_deep_free(hashed_sname); tmp = sname; sname = ldns_dname_left_chop(sname); ldns_rdf_deep_free(tmp); } done: LDNS_FREE(salt); ldns_rdf_deep_free(zone_name); ldns_rdf_deep_free(sname); return result; } bool ldns_dnssec_pkt_has_rrsigs(const ldns_pkt *pkt) { size_t i; for (i = 0; i < ldns_pkt_ancount(pkt); i++) { if (ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_answer(pkt), i)) == LDNS_RR_TYPE_RRSIG) { return true; } } for (i = 0; i < ldns_pkt_nscount(pkt); i++) { if (ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_authority(pkt), i)) == LDNS_RR_TYPE_RRSIG) { return true; } } return false; } ldns_rr_list * ldns_dnssec_pkt_get_rrsigs_for_name_and_type(const ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type) { uint16_t t_netorder; ldns_rr_list *sigs; ldns_rr_list *sigs_covered; ldns_rdf *rdf_t; sigs = ldns_pkt_rr_list_by_name_and_type(pkt, name, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION ); t_netorder = htons(type); /* rdf are in network order! */ rdf_t = ldns_rdf_new(LDNS_RDF_TYPE_TYPE, LDNS_RDF_SIZE_WORD, &t_netorder); sigs_covered = ldns_rr_list_subtype_by_rdf(sigs, rdf_t, 0); ldns_rdf_free(rdf_t); ldns_rr_list_deep_free(sigs); return sigs_covered; } ldns_rr_list * ldns_dnssec_pkt_get_rrsigs_for_type(const ldns_pkt *pkt, ldns_rr_type type) { uint16_t t_netorder; ldns_rr_list *sigs; ldns_rr_list *sigs_covered; ldns_rdf *rdf_t; sigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION ); t_netorder = htons(type); /* rdf are in network order! */ rdf_t = ldns_rdf_new(LDNS_RDF_TYPE_TYPE, 2, &t_netorder); sigs_covered = ldns_rr_list_subtype_by_rdf(sigs, rdf_t, 0); ldns_rdf_free(rdf_t); ldns_rr_list_deep_free(sigs); return sigs_covered; } /* used only on the public key RR */ uint16_t ldns_calc_keytag(const ldns_rr *key) { uint16_t ac16; ldns_buffer *keybuf; size_t keysize; if (!key) { return 0; } if (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY && ldns_rr_get_type(key) != LDNS_RR_TYPE_KEY ) { return 0; } /* rdata to buf - only put the rdata in a buffer */ keybuf = ldns_buffer_new(LDNS_MIN_BUFLEN); /* grows */ if (!keybuf) { return 0; } (void)ldns_rr_rdata2buffer_wire(keybuf, key); /* the current pos in the buffer is the keysize */ keysize= ldns_buffer_position(keybuf); ac16 = ldns_calc_keytag_raw(ldns_buffer_begin(keybuf), keysize); ldns_buffer_free(keybuf); return ac16; } uint16_t ldns_calc_keytag_raw(uint8_t* key, size_t keysize) { unsigned int i; uint32_t ac32; uint16_t ac16; if(keysize < 4) { return 0; } /* look at the algorithm field, copied from 2535bis */ if (key[3] == LDNS_RSAMD5) { ac16 = 0; if (keysize > 4) { memmove(&ac16, key + keysize - 3, 2); } ac16 = ntohs(ac16); return (uint16_t) ac16; } else { ac32 = 0; for (i = 0; (size_t)i < keysize; ++i) { ac32 += (i & 1) ? key[i] : key[i] << 8; } ac32 += (ac32 >> 16) & 0xFFFF; return (uint16_t) (ac32 & 0xFFFF); } } #ifdef HAVE_SSL DSA * ldns_key_buf2dsa(ldns_buffer *key) { return ldns_key_buf2dsa_raw((unsigned char*)ldns_buffer_begin(key), ldns_buffer_position(key)); } DSA * ldns_key_buf2dsa_raw(unsigned char* key, size_t len) { uint8_t T; uint16_t length; uint16_t offset; DSA *dsa; BIGNUM *Q; BIGNUM *P; BIGNUM *G; BIGNUM *Y; if(len == 0) return NULL; T = (uint8_t)key[0]; length = (64 + T * 8); offset = 1; if (T > 8) { return NULL; } if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length) return NULL; Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL); offset += SHA_DIGEST_LENGTH; P = BN_bin2bn(key+offset, (int)length, NULL); offset += length; G = BN_bin2bn(key+offset, (int)length, NULL); offset += length; Y = BN_bin2bn(key+offset, (int)length, NULL); offset += length; /* create the key and set its properties */ if(!Q || !P || !G || !Y || !(dsa = DSA_new())) { BN_free(Q); BN_free(P); BN_free(G); BN_free(Y); return NULL; } #ifndef S_SPLINT_S dsa->p = P; dsa->q = Q; dsa->g = G; dsa->pub_key = Y; #endif /* splint */ return dsa; } RSA * ldns_key_buf2rsa(ldns_buffer *key) { return ldns_key_buf2rsa_raw((unsigned char*)ldns_buffer_begin(key), ldns_buffer_position(key)); } RSA * ldns_key_buf2rsa_raw(unsigned char* key, size_t len) { uint16_t offset; uint16_t exp; uint16_t int16; RSA *rsa; BIGNUM *modulus; BIGNUM *exponent; if (len == 0) return NULL; if (key[0] == 0) { if(len < 3) return NULL; /* need some smart comment here XXX*/ /* the exponent is too large so it's places * futher...???? */ memmove(&int16, key+1, 2); exp = ntohs(int16); offset = 3; } else { exp = key[0]; offset = 1; } /* key length at least one */ if(len < (size_t)offset + exp + 1) return NULL; /* Exponent */ exponent = BN_new(); if(!exponent) return NULL; (void) BN_bin2bn(key+offset, (int)exp, exponent); offset += exp; /* Modulus */ modulus = BN_new(); if(!modulus) { BN_free(exponent); return NULL; } /* length of the buffer must match the key length! */ (void) BN_bin2bn(key+offset, (int)(len - offset), modulus); rsa = RSA_new(); if(!rsa) { BN_free(exponent); BN_free(modulus); return NULL; } #ifndef S_SPLINT_S rsa->n = modulus; rsa->e = exponent; #endif /* splint */ return rsa; } int ldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest, const EVP_MD* md) { EVP_MD_CTX* ctx; ctx = EVP_MD_CTX_create(); if(!ctx) return false; if(!EVP_DigestInit_ex(ctx, md, NULL) || !EVP_DigestUpdate(ctx, data, len) || !EVP_DigestFinal_ex(ctx, dest, NULL)) { EVP_MD_CTX_destroy(ctx); return false; } EVP_MD_CTX_destroy(ctx); return true; } #endif /* HAVE_SSL */ ldns_rr * ldns_key_rr2ds(const ldns_rr *key, ldns_hash h) { ldns_rdf *tmp; ldns_rr *ds; uint16_t keytag; uint8_t sha1hash; uint8_t *digest; ldns_buffer *data_buf; #ifdef USE_GOST const EVP_MD* md = NULL; #endif if (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY) { return NULL; } ds = ldns_rr_new(); if (!ds) { return NULL; } ldns_rr_set_type(ds, LDNS_RR_TYPE_DS); ldns_rr_set_owner(ds, ldns_rdf_clone( ldns_rr_owner(key))); ldns_rr_set_ttl(ds, ldns_rr_ttl(key)); ldns_rr_set_class(ds, ldns_rr_get_class(key)); switch(h) { default: case LDNS_SHA1: digest = LDNS_XMALLOC(uint8_t, LDNS_SHA1_DIGEST_LENGTH); if (!digest) { ldns_rr_free(ds); return NULL; } break; case LDNS_SHA256: digest = LDNS_XMALLOC(uint8_t, LDNS_SHA256_DIGEST_LENGTH); if (!digest) { ldns_rr_free(ds); return NULL; } break; case LDNS_HASH_GOST: #ifdef USE_GOST (void)ldns_key_EVP_load_gost_id(); md = EVP_get_digestbyname("md_gost94"); if(!md) { ldns_rr_free(ds); return NULL; } digest = LDNS_XMALLOC(uint8_t, EVP_MD_size(md)); if (!digest) { ldns_rr_free(ds); return NULL; } break; #else /* not implemented */ ldns_rr_free(ds); return NULL; #endif case LDNS_SHA384: #ifdef USE_ECDSA digest = LDNS_XMALLOC(uint8_t, SHA384_DIGEST_LENGTH); if (!digest) { ldns_rr_free(ds); return NULL; } break; #else /* not implemented */ ldns_rr_free(ds); return NULL; #endif } data_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!data_buf) { LDNS_FREE(digest); ldns_rr_free(ds); return NULL; } /* keytag */ keytag = htons(ldns_calc_keytag((ldns_rr*)key)); tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT16, sizeof(uint16_t), &keytag); ldns_rr_push_rdf(ds, tmp); /* copy the algorithm field */ if ((tmp = ldns_rr_rdf(key, 2)) == NULL) { LDNS_FREE(digest); ldns_buffer_free(data_buf); ldns_rr_free(ds); return NULL; } else { ldns_rr_push_rdf(ds, ldns_rdf_clone( tmp )); } /* digest hash type */ sha1hash = (uint8_t)h; tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8, sizeof(uint8_t), &sha1hash); ldns_rr_push_rdf(ds, tmp); /* digest */ /* owner name */ tmp = ldns_rdf_clone(ldns_rr_owner(key)); ldns_dname2canonical(tmp); if (ldns_rdf2buffer_wire(data_buf, tmp) != LDNS_STATUS_OK) { LDNS_FREE(digest); ldns_buffer_free(data_buf); ldns_rr_free(ds); ldns_rdf_deep_free(tmp); return NULL; } ldns_rdf_deep_free(tmp); /* all the rdata's */ if (ldns_rr_rdata2buffer_wire(data_buf, (ldns_rr*)key) != LDNS_STATUS_OK) { LDNS_FREE(digest); ldns_buffer_free(data_buf); ldns_rr_free(ds); return NULL; } switch(h) { case LDNS_SHA1: (void) ldns_sha1((unsigned char *) ldns_buffer_begin(data_buf), (unsigned int) ldns_buffer_position(data_buf), (unsigned char *) digest); tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX, LDNS_SHA1_DIGEST_LENGTH, digest); ldns_rr_push_rdf(ds, tmp); break; case LDNS_SHA256: (void) ldns_sha256((unsigned char *) ldns_buffer_begin(data_buf), (unsigned int) ldns_buffer_position(data_buf), (unsigned char *) digest); tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX, LDNS_SHA256_DIGEST_LENGTH, digest); ldns_rr_push_rdf(ds, tmp); break; case LDNS_HASH_GOST: #ifdef USE_GOST if(!ldns_digest_evp((unsigned char *) ldns_buffer_begin(data_buf), (unsigned int) ldns_buffer_position(data_buf), (unsigned char *) digest, md)) { LDNS_FREE(digest); ldns_buffer_free(data_buf); ldns_rr_free(ds); return NULL; } tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX, (size_t)EVP_MD_size(md), digest); ldns_rr_push_rdf(ds, tmp); #endif break; case LDNS_SHA384: #ifdef USE_ECDSA (void) SHA384((unsigned char *) ldns_buffer_begin(data_buf), (unsigned int) ldns_buffer_position(data_buf), (unsigned char *) digest); tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX, SHA384_DIGEST_LENGTH, digest); ldns_rr_push_rdf(ds, tmp); #endif break; } LDNS_FREE(digest); ldns_buffer_free(data_buf); return ds; } /* From RFC3845: * * 2.1.2. The List of Type Bit Map(s) Field * * The RR type space is split into 256 window blocks, each representing * the low-order 8 bits of the 16-bit RR type space. Each block that * has at least one active RR type is encoded using a single octet * window number (from 0 to 255), a single octet bitmap length (from 1 * to 32) indicating the number of octets used for the window block's * bitmap, and up to 32 octets (256 bits) of bitmap. * * Window blocks are present in the NSEC RR RDATA in increasing * numerical order. * * "|" denotes concatenation * * Type Bit Map(s) Field = ( Window Block # | Bitmap Length | Bitmap ) + * * * * Blocks with no types present MUST NOT be included. Trailing zero * octets in the bitmap MUST be omitted. The length of each block's * bitmap is determined by the type code with the largest numerical * value within that block, among the set of RR types present at the * NSEC RR's owner name. Trailing zero octets not specified MUST be * interpreted as zero octets. */ ldns_rdf * ldns_dnssec_create_nsec_bitmap(ldns_rr_type rr_type_list[], size_t size, ldns_rr_type nsec_type) { uint8_t window; /* most significant octet of type */ uint8_t subtype; /* least significant octet of type */ uint16_t windows[256] /* Max subtype per window */ #ifndef S_SPLINT_S = { 0 } /* Initialize ALL elements with 0 */ #endif ; ldns_rr_type* d; /* used to traverse rr_type_list*/ size_t i; /* used to traverse windows array */ size_t sz; /* size needed for type bitmap rdf */ uint8_t* data = NULL; /* rdf data */ uint8_t* dptr; /* used to itraverse rdf data */ ldns_rdf* rdf; /* bitmap rdf to return */ if (nsec_type != LDNS_RR_TYPE_NSEC && nsec_type != LDNS_RR_TYPE_NSEC3) { return NULL; } /* Which other windows need to be in the bitmap rdf? */ for (d = rr_type_list; d < rr_type_list + size; d++) { window = *d >> 8; subtype = *d & 0xff; if (windows[window] < subtype) { windows[window] = subtype; } } /* How much space do we need in the rdf for those windows? */ sz = 0; for (i = 0; i < 256; i++) { if (windows[i]) { sz += windows[i] / 8 + 3; } } if (sz > 0) { /* Format rdf data according RFC3845 Section 2.1.2 (see above) */ dptr = data = LDNS_CALLOC(uint8_t, sz); if (!data) { return NULL; } for (i = 0; i < 256; i++) { if (windows[i]) { *dptr++ = (uint8_t)i; *dptr++ = (uint8_t)(windows[i] / 8 + 1); /* Now let windows[i] index the bitmap * within data */ windows[i] = (uint16_t)(dptr - data); dptr += dptr[-1]; } } } /* Set the bits? */ for (d = rr_type_list; d < rr_type_list + size; d++) { subtype = *d & 0xff; data[windows[*d >> 8] + subtype/8] |= (0x80 >> (subtype % 8)); } /* Allocate and return rdf structure for the data */ rdf = ldns_rdf_new(LDNS_RDF_TYPE_BITMAP, sz, data); if (!rdf) { LDNS_FREE(data); return NULL; } return rdf; } int ldns_dnssec_rrsets_contains_type(ldns_dnssec_rrsets *rrsets, ldns_rr_type type) { ldns_dnssec_rrsets *cur_rrset = rrsets; while (cur_rrset) { if (cur_rrset->type == type) { return 1; } cur_rrset = cur_rrset->next; } return 0; } ldns_rr * ldns_dnssec_create_nsec(ldns_dnssec_name *from, ldns_dnssec_name *to, ldns_rr_type nsec_type) { ldns_rr *nsec_rr; ldns_rr_type types[65536]; size_t type_count = 0; ldns_dnssec_rrsets *cur_rrsets; int on_delegation_point; if (!from || !to || (nsec_type != LDNS_RR_TYPE_NSEC)) { return NULL; } nsec_rr = ldns_rr_new(); ldns_rr_set_type(nsec_rr, nsec_type); ldns_rr_set_owner(nsec_rr, ldns_rdf_clone(ldns_dnssec_name_name(from))); ldns_rr_push_rdf(nsec_rr, ldns_rdf_clone(ldns_dnssec_name_name(to))); on_delegation_point = ldns_dnssec_rrsets_contains_type( from->rrsets, LDNS_RR_TYPE_NS) && !ldns_dnssec_rrsets_contains_type( from->rrsets, LDNS_RR_TYPE_SOA); cur_rrsets = from->rrsets; while (cur_rrsets) { /* Do not include non-authoritative rrsets on the delegation point * in the type bitmap */ if ((on_delegation_point && ( cur_rrsets->type == LDNS_RR_TYPE_NS || cur_rrsets->type == LDNS_RR_TYPE_DS)) || (!on_delegation_point && cur_rrsets->type != LDNS_RR_TYPE_RRSIG && cur_rrsets->type != LDNS_RR_TYPE_NSEC)) { types[type_count] = cur_rrsets->type; type_count++; } cur_rrsets = cur_rrsets->next; } types[type_count] = LDNS_RR_TYPE_RRSIG; type_count++; types[type_count] = LDNS_RR_TYPE_NSEC; type_count++; ldns_rr_push_rdf(nsec_rr, ldns_dnssec_create_nsec_bitmap(types, type_count, nsec_type)); return nsec_rr; } ldns_rr * ldns_dnssec_create_nsec3(ldns_dnssec_name *from, ldns_dnssec_name *to, ldns_rdf *zone_name, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt) { ldns_rr *nsec_rr; ldns_rr_type types[65536]; size_t type_count = 0; ldns_dnssec_rrsets *cur_rrsets; ldns_status status; int on_delegation_point; if (!from) { return NULL; } nsec_rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3); ldns_rr_set_owner(nsec_rr, ldns_nsec3_hash_name(ldns_dnssec_name_name(from), algorithm, iterations, salt_length, salt)); status = ldns_dname_cat(ldns_rr_owner(nsec_rr), zone_name); if(status != LDNS_STATUS_OK) { ldns_rr_free(nsec_rr); return NULL; } ldns_nsec3_add_param_rdfs(nsec_rr, algorithm, flags, iterations, salt_length, salt); on_delegation_point = ldns_dnssec_rrsets_contains_type( from->rrsets, LDNS_RR_TYPE_NS) && !ldns_dnssec_rrsets_contains_type( from->rrsets, LDNS_RR_TYPE_SOA); cur_rrsets = from->rrsets; while (cur_rrsets) { /* Do not include non-authoritative rrsets on the delegation point * in the type bitmap. Potentionally not skipping insecure * delegation should have been done earlier, in function * ldns_dnssec_zone_create_nsec3s, or even earlier in: * ldns_dnssec_zone_sign_nsec3_flg . */ if ((on_delegation_point && ( cur_rrsets->type == LDNS_RR_TYPE_NS || cur_rrsets->type == LDNS_RR_TYPE_DS)) || (!on_delegation_point && cur_rrsets->type != LDNS_RR_TYPE_RRSIG)) { types[type_count] = cur_rrsets->type; type_count++; } cur_rrsets = cur_rrsets->next; } /* always add rrsig type if this is not an unsigned * delegation */ if (type_count > 0 && !(type_count == 1 && types[0] == LDNS_RR_TYPE_NS)) { types[type_count] = LDNS_RR_TYPE_RRSIG; type_count++; } /* leave next rdata empty if they weren't precomputed yet */ if (to && to->hashed_name) { (void) ldns_rr_set_rdf(nsec_rr, ldns_rdf_clone(to->hashed_name), 4); } else { (void) ldns_rr_set_rdf(nsec_rr, NULL, 4); } ldns_rr_push_rdf(nsec_rr, ldns_dnssec_create_nsec_bitmap(types, type_count, LDNS_RR_TYPE_NSEC3)); return nsec_rr; } ldns_rr * ldns_create_nsec(ldns_rdf *cur_owner, ldns_rdf *next_owner, ldns_rr_list *rrs) { /* we do not do any check here - garbage in, garbage out */ /* the the start and end names - get the type from the * before rrlist */ /* inefficient, just give it a name, a next name, and a list of rrs */ /* we make 1 big uberbitmap first, then windows */ /* todo: make something more efficient :) */ uint16_t i; ldns_rr *i_rr; uint16_t i_type; ldns_rr *nsec = NULL; ldns_rr_type i_type_list[65536]; size_t type_count = 0; nsec = ldns_rr_new(); ldns_rr_set_type(nsec, LDNS_RR_TYPE_NSEC); ldns_rr_set_owner(nsec, ldns_rdf_clone(cur_owner)); ldns_rr_push_rdf(nsec, ldns_rdf_clone(next_owner)); for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) { i_rr = ldns_rr_list_rr(rrs, i); if (ldns_rdf_compare(cur_owner, ldns_rr_owner(i_rr)) == 0) { i_type = ldns_rr_get_type(i_rr); if (i_type != LDNS_RR_TYPE_RRSIG && i_type != LDNS_RR_TYPE_NSEC) { if (type_count == 0 || i_type_list[type_count-1] != i_type) { i_type_list[type_count] = i_type; type_count++; } } } } i_type_list[type_count] = LDNS_RR_TYPE_RRSIG; type_count++; i_type_list[type_count] = LDNS_RR_TYPE_NSEC; type_count++; ldns_rr_push_rdf(nsec, ldns_dnssec_create_nsec_bitmap(i_type_list, type_count, LDNS_RR_TYPE_NSEC)); return nsec; } ldns_rdf * ldns_nsec3_hash_name(ldns_rdf *name, uint8_t algorithm, uint16_t iterations, uint8_t salt_length, uint8_t *salt) { size_t hashed_owner_str_len; ldns_rdf *cann; ldns_rdf *hashed_owner; unsigned char *hashed_owner_str; char *hashed_owner_b32; size_t hashed_owner_b32_len; uint32_t cur_it; /* define to contain the largest possible hash, which is * sha1 at the moment */ unsigned char hash[LDNS_SHA1_DIGEST_LENGTH]; ldns_status status; /* TODO: mnemonic list for hash algs SHA-1, default to 1 now (sha1) */ if (algorithm != LDNS_SHA1) { return NULL; } /* prepare the owner name according to the draft section bla */ cann = ldns_rdf_clone(name); if(!cann) { #ifdef STDERR_MSGS fprintf(stderr, "Memory error\n"); #endif return NULL; } ldns_dname2canonical(cann); hashed_owner_str_len = salt_length + ldns_rdf_size(cann); hashed_owner_str = LDNS_XMALLOC(unsigned char, hashed_owner_str_len); if(!hashed_owner_str) { ldns_rdf_deep_free(cann); return NULL; } memcpy(hashed_owner_str, ldns_rdf_data(cann), ldns_rdf_size(cann)); memcpy(hashed_owner_str + ldns_rdf_size(cann), salt, salt_length); ldns_rdf_deep_free(cann); for (cur_it = iterations + 1; cur_it > 0; cur_it--) { (void) ldns_sha1((unsigned char *) hashed_owner_str, (unsigned int) hashed_owner_str_len, hash); LDNS_FREE(hashed_owner_str); hashed_owner_str_len = salt_length + LDNS_SHA1_DIGEST_LENGTH; hashed_owner_str = LDNS_XMALLOC(unsigned char, hashed_owner_str_len); if (!hashed_owner_str) { return NULL; } memcpy(hashed_owner_str, hash, LDNS_SHA1_DIGEST_LENGTH); memcpy(hashed_owner_str + LDNS_SHA1_DIGEST_LENGTH, salt, salt_length); hashed_owner_str_len = LDNS_SHA1_DIGEST_LENGTH + salt_length; } LDNS_FREE(hashed_owner_str); hashed_owner_str = hash; hashed_owner_str_len = LDNS_SHA1_DIGEST_LENGTH; hashed_owner_b32 = LDNS_XMALLOC(char, ldns_b32_ntop_calculate_size(hashed_owner_str_len) + 1); if(!hashed_owner_b32) { return NULL; } hashed_owner_b32_len = (size_t) ldns_b32_ntop_extended_hex( (uint8_t *) hashed_owner_str, hashed_owner_str_len, hashed_owner_b32, ldns_b32_ntop_calculate_size(hashed_owner_str_len)+1); if (hashed_owner_b32_len < 1) { #ifdef STDERR_MSGS fprintf(stderr, "Error in base32 extended hex encoding "); fprintf(stderr, "of hashed owner name (name: "); ldns_rdf_print(stderr, name); fprintf(stderr, ", return code: %u)\n", (unsigned int) hashed_owner_b32_len); #endif LDNS_FREE(hashed_owner_b32); return NULL; } hashed_owner_b32[hashed_owner_b32_len] = '\0'; status = ldns_str2rdf_dname(&hashed_owner, hashed_owner_b32); if (status != LDNS_STATUS_OK) { #ifdef STDERR_MSGS fprintf(stderr, "Error creating rdf from %s\n", hashed_owner_b32); #endif LDNS_FREE(hashed_owner_b32); return NULL; } LDNS_FREE(hashed_owner_b32); return hashed_owner; } void ldns_nsec3_add_param_rdfs(ldns_rr *rr, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt) { ldns_rdf *salt_rdf = NULL; uint8_t *salt_data = NULL; ldns_rdf *old; old = ldns_rr_set_rdf(rr, ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8, 1, (void*)&algorithm), 0); if (old) ldns_rdf_deep_free(old); old = ldns_rr_set_rdf(rr, ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8, 1, (void*)&flags), 1); if (old) ldns_rdf_deep_free(old); old = ldns_rr_set_rdf(rr, ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, iterations), 2); if (old) ldns_rdf_deep_free(old); salt_data = LDNS_XMALLOC(uint8_t, salt_length + 1); if(!salt_data) { /* no way to return error */ return; } salt_data[0] = salt_length; memcpy(salt_data + 1, salt, salt_length); salt_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC3_SALT, salt_length + 1, salt_data); if(!salt_rdf) { LDNS_FREE(salt_data); /* no way to return error */ return; } old = ldns_rr_set_rdf(rr, salt_rdf, 3); if (old) ldns_rdf_deep_free(old); LDNS_FREE(salt_data); } static int rr_list_delegation_only(ldns_rdf *origin, ldns_rr_list *rr_list) { size_t i; ldns_rr *cur_rr; if (!origin || !rr_list) return 0; for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { cur_rr = ldns_rr_list_rr(rr_list, i); if (ldns_dname_compare(ldns_rr_owner(cur_rr), origin) == 0) { return 0; } if (ldns_rr_get_type(cur_rr) != LDNS_RR_TYPE_NS) { return 0; } } return 1; } /* this will NOT return the NSEC3 completed, you will have to run the finalize function on the rrlist later! */ ldns_rr * ldns_create_nsec3(ldns_rdf *cur_owner, ldns_rdf *cur_zone, ldns_rr_list *rrs, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt, bool emptynonterminal) { size_t i; ldns_rr *i_rr; uint16_t i_type; ldns_rr *nsec = NULL; ldns_rdf *hashed_owner = NULL; ldns_status status; ldns_rr_type i_type_list[1024]; size_t type_count = 0; hashed_owner = ldns_nsec3_hash_name(cur_owner, algorithm, iterations, salt_length, salt); status = ldns_dname_cat(hashed_owner, cur_zone); if(status != LDNS_STATUS_OK) { ldns_rdf_deep_free(hashed_owner); return NULL; } nsec = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3); if(!nsec) { ldns_rdf_deep_free(hashed_owner); return NULL; } ldns_rr_set_type(nsec, LDNS_RR_TYPE_NSEC3); ldns_rr_set_owner(nsec, hashed_owner); ldns_nsec3_add_param_rdfs(nsec, algorithm, flags, iterations, salt_length, salt); (void) ldns_rr_set_rdf(nsec, NULL, 4); for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) { i_rr = ldns_rr_list_rr(rrs, i); if (ldns_rdf_compare(cur_owner, ldns_rr_owner(i_rr)) == 0) { i_type = ldns_rr_get_type(i_rr); if (type_count == 0 || i_type_list[type_count-1] != i_type) { i_type_list[type_count] = i_type; type_count++; } } } /* add RRSIG anyway, but only if this is not an ENT or * an unsigned delegation */ if (!emptynonterminal && !rr_list_delegation_only(cur_zone, rrs)) { i_type_list[type_count] = LDNS_RR_TYPE_RRSIG; type_count++; } /* and SOA if owner == zone */ if (ldns_dname_compare(cur_zone, cur_owner) == 0) { i_type_list[type_count] = LDNS_RR_TYPE_SOA; type_count++; } ldns_rr_push_rdf(nsec, ldns_dnssec_create_nsec_bitmap(i_type_list, type_count, LDNS_RR_TYPE_NSEC3)); return nsec; } uint8_t ldns_nsec3_algorithm(const ldns_rr *nsec3_rr) { if (nsec3_rr && (ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 || ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM) && (ldns_rr_rdf(nsec3_rr, 0) != NULL) && ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 0)) > 0) { return ldns_rdf2native_int8(ldns_rr_rdf(nsec3_rr, 0)); } return 0; } uint8_t ldns_nsec3_flags(const ldns_rr *nsec3_rr) { if (nsec3_rr && (ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 || ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM) && (ldns_rr_rdf(nsec3_rr, 1) != NULL) && ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 1)) > 0) { return ldns_rdf2native_int8(ldns_rr_rdf(nsec3_rr, 1)); } return 0; } bool ldns_nsec3_optout(const ldns_rr *nsec3_rr) { return (ldns_nsec3_flags(nsec3_rr) & LDNS_NSEC3_VARS_OPTOUT_MASK); } uint16_t ldns_nsec3_iterations(const ldns_rr *nsec3_rr) { if (nsec3_rr && (ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 || ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM) && (ldns_rr_rdf(nsec3_rr, 2) != NULL) && ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 2)) > 0) { return ldns_rdf2native_int16(ldns_rr_rdf(nsec3_rr, 2)); } return 0; } ldns_rdf * ldns_nsec3_salt(const ldns_rr *nsec3_rr) { if (nsec3_rr && (ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 || ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM) ) { return ldns_rr_rdf(nsec3_rr, 3); } return NULL; } uint8_t ldns_nsec3_salt_length(const ldns_rr *nsec3_rr) { ldns_rdf *salt_rdf = ldns_nsec3_salt(nsec3_rr); if (salt_rdf && ldns_rdf_size(salt_rdf) > 0) { return (uint8_t) ldns_rdf_data(salt_rdf)[0]; } return 0; } /* allocs data, free with LDNS_FREE() */ uint8_t * ldns_nsec3_salt_data(const ldns_rr *nsec3_rr) { uint8_t salt_length; uint8_t *salt; ldns_rdf *salt_rdf = ldns_nsec3_salt(nsec3_rr); if (salt_rdf && ldns_rdf_size(salt_rdf) > 0) { salt_length = ldns_rdf_data(salt_rdf)[0]; salt = LDNS_XMALLOC(uint8_t, salt_length); if(!salt) return NULL; memcpy(salt, &ldns_rdf_data(salt_rdf)[1], salt_length); return salt; } return NULL; } ldns_rdf * ldns_nsec3_next_owner(const ldns_rr *nsec3_rr) { if (!nsec3_rr || ldns_rr_get_type(nsec3_rr) != LDNS_RR_TYPE_NSEC3) { return NULL; } else { return ldns_rr_rdf(nsec3_rr, 4); } } ldns_rdf * ldns_nsec3_bitmap(const ldns_rr *nsec3_rr) { if (!nsec3_rr || ldns_rr_get_type(nsec3_rr) != LDNS_RR_TYPE_NSEC3) { return NULL; } else { return ldns_rr_rdf(nsec3_rr, 5); } } ldns_rdf * ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, ldns_rdf *name) { uint8_t algorithm; uint16_t iterations; uint8_t salt_length; uint8_t *salt = 0; ldns_rdf *hashed_owner; algorithm = ldns_nsec3_algorithm(nsec); salt_length = ldns_nsec3_salt_length(nsec); salt = ldns_nsec3_salt_data(nsec); iterations = ldns_nsec3_iterations(nsec); hashed_owner = ldns_nsec3_hash_name(name, algorithm, iterations, salt_length, salt); LDNS_FREE(salt); return hashed_owner; } bool ldns_nsec_bitmap_covers_type(const ldns_rdf* bitmap, ldns_rr_type type) { uint8_t* dptr; uint8_t* dend; /* From RFC3845 Section 2.1.2: * * "The RR type space is split into 256 window blocks, each re- * presenting the low-order 8 bits of the 16-bit RR type space." */ uint8_t window = type >> 8; uint8_t subtype = type & 0xff; if (! bitmap) { return false; } assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP); dptr = ldns_rdf_data(bitmap); dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap); /* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) + * dptr[0] dptr[1] dptr[2:] */ while (dptr < dend && dptr[0] <= window) { if (dptr[0] == window && subtype / 8 < dptr[1] && dptr + dptr[1] + 2 <= dend) { return dptr[2 + subtype / 8] & (0x80 >> (subtype % 8)); } dptr += dptr[1] + 2; /* next window */ } return false; } ldns_status ldns_nsec_bitmap_set_type(ldns_rdf* bitmap, ldns_rr_type type) { uint8_t* dptr; uint8_t* dend; /* From RFC3845 Section 2.1.2: * * "The RR type space is split into 256 window blocks, each re- * presenting the low-order 8 bits of the 16-bit RR type space." */ uint8_t window = type >> 8; uint8_t subtype = type & 0xff; if (! bitmap) { return false; } assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP); dptr = ldns_rdf_data(bitmap); dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap); /* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) + * dptr[0] dptr[1] dptr[2:] */ while (dptr < dend && dptr[0] <= window) { if (dptr[0] == window && subtype / 8 < dptr[1] && dptr + dptr[1] + 2 <= dend) { dptr[2 + subtype / 8] |= (0x80 >> (subtype % 8)); return LDNS_STATUS_OK; } dptr += dptr[1] + 2; /* next window */ } return LDNS_STATUS_TYPE_NOT_IN_BITMAP; } ldns_status ldns_nsec_bitmap_clear_type(ldns_rdf* bitmap, ldns_rr_type type) { uint8_t* dptr; uint8_t* dend; /* From RFC3845 Section 2.1.2: * * "The RR type space is split into 256 window blocks, each re- * presenting the low-order 8 bits of the 16-bit RR type space." */ uint8_t window = type >> 8; uint8_t subtype = type & 0xff; if (! bitmap) { return false; } assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP); dptr = ldns_rdf_data(bitmap); dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap); /* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) + * dptr[0] dptr[1] dptr[2:] */ while (dptr < dend && dptr[0] <= window) { if (dptr[0] == window && subtype / 8 < dptr[1] && dptr + dptr[1] + 2 <= dend) { dptr[2 + subtype / 8] &= ~(0x80 >> (subtype % 8)); return LDNS_STATUS_OK; } dptr += dptr[1] + 2; /* next window */ } return LDNS_STATUS_TYPE_NOT_IN_BITMAP; } bool ldns_nsec_covers_name(const ldns_rr *nsec, const ldns_rdf *name) { ldns_rdf *nsec_owner = ldns_rr_owner(nsec); ldns_rdf *hash_next; char *next_hash_str; ldns_rdf *nsec_next = NULL; ldns_status status; ldns_rdf *chopped_dname; bool result; if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC) { if (ldns_rr_rdf(nsec, 0) != NULL) { nsec_next = ldns_rdf_clone(ldns_rr_rdf(nsec, 0)); } else { return false; } } else if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC3) { hash_next = ldns_nsec3_next_owner(nsec); next_hash_str = ldns_rdf2str(hash_next); nsec_next = ldns_dname_new_frm_str(next_hash_str); LDNS_FREE(next_hash_str); chopped_dname = ldns_dname_left_chop(nsec_owner); status = ldns_dname_cat(nsec_next, chopped_dname); ldns_rdf_deep_free(chopped_dname); if (status != LDNS_STATUS_OK) { printf("error catting: %s\n", ldns_get_errorstr_by_id(status)); } } else { ldns_rdf_deep_free(nsec_next); return false; } /* in the case of the last nsec */ if(ldns_dname_compare(nsec_owner, nsec_next) > 0) { result = (ldns_dname_compare(nsec_owner, name) <= 0 || ldns_dname_compare(name, nsec_next) < 0); } else if(ldns_dname_compare(nsec_owner, nsec_next) < 0) { result = (ldns_dname_compare(nsec_owner, name) <= 0 && ldns_dname_compare(name, nsec_next) < 0); } else { result = true; } ldns_rdf_deep_free(nsec_next); return result; } #ifdef HAVE_SSL /* sig may be null - if so look in the packet */ ldns_status ldns_pkt_verify_time(ldns_pkt *p, ldns_rr_type t, ldns_rdf *o, ldns_rr_list *k, ldns_rr_list *s, time_t check_time, ldns_rr_list *good_keys) { ldns_rr_list *rrset; ldns_rr_list *sigs; ldns_rr_list *sigs_covered; ldns_rdf *rdf_t; ldns_rr_type t_netorder; if (!k) { return LDNS_STATUS_ERR; /* return LDNS_STATUS_CRYPTO_NO_DNSKEY; */ } if (t == LDNS_RR_TYPE_RRSIG) { /* we don't have RRSIG(RRSIG) (yet? ;-) ) */ return LDNS_STATUS_ERR; } if (s) { /* if s is not NULL, the sigs are given to use */ sigs = s; } else { /* otherwise get them from the packet */ sigs = ldns_pkt_rr_list_by_name_and_type(p, o, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION); if (!sigs) { /* no sigs */ return LDNS_STATUS_ERR; /* return LDNS_STATUS_CRYPTO_NO_RRSIG; */ } } /* rrsig are subtyped, so now we need to find the correct * sigs for the type t */ t_netorder = htons(t); /* rdf are in network order! */ /* a type identifier is a 16-bit number, so the size is 2 bytes */ rdf_t = ldns_rdf_new(LDNS_RDF_TYPE_TYPE, 2, &t_netorder); sigs_covered = ldns_rr_list_subtype_by_rdf(sigs, rdf_t, 0); ldns_rdf_free(rdf_t); if (! sigs_covered) { if (! s) { ldns_rr_list_deep_free(sigs); } return LDNS_STATUS_ERR; } ldns_rr_list_deep_free(sigs_covered); rrset = ldns_pkt_rr_list_by_name_and_type(p, o, t, LDNS_SECTION_ANY_NOQUESTION); if (!rrset) { if (! s) { ldns_rr_list_deep_free(sigs); } return LDNS_STATUS_ERR; } return ldns_verify_time(rrset, sigs, k, check_time, good_keys); } ldns_status ldns_pkt_verify(ldns_pkt *p, ldns_rr_type t, ldns_rdf *o, ldns_rr_list *k, ldns_rr_list *s, ldns_rr_list *good_keys) { return ldns_pkt_verify_time(p, t, o, k, s, ldns_time(NULL), good_keys); } #endif /* HAVE_SSL */ ldns_status ldns_dnssec_chain_nsec3_list(ldns_rr_list *nsec3_rrs) { size_t i; char *next_nsec_owner_str; ldns_rdf *next_nsec_owner_label; ldns_rdf *next_nsec_rdf; ldns_status status = LDNS_STATUS_OK; for (i = 0; i < ldns_rr_list_rr_count(nsec3_rrs); i++) { if (i == ldns_rr_list_rr_count(nsec3_rrs) - 1) { next_nsec_owner_label = ldns_dname_label(ldns_rr_owner(ldns_rr_list_rr(nsec3_rrs, 0)), 0); next_nsec_owner_str = ldns_rdf2str(next_nsec_owner_label); if (next_nsec_owner_str[strlen(next_nsec_owner_str) - 1] == '.') { next_nsec_owner_str[strlen(next_nsec_owner_str) - 1] = '\0'; } status = ldns_str2rdf_b32_ext(&next_nsec_rdf, next_nsec_owner_str); if (!ldns_rr_set_rdf(ldns_rr_list_rr(nsec3_rrs, i), next_nsec_rdf, 4)) { /* todo: error */ } ldns_rdf_deep_free(next_nsec_owner_label); LDNS_FREE(next_nsec_owner_str); } else { next_nsec_owner_label = ldns_dname_label(ldns_rr_owner(ldns_rr_list_rr(nsec3_rrs, i + 1)), 0); next_nsec_owner_str = ldns_rdf2str(next_nsec_owner_label); if (next_nsec_owner_str[strlen(next_nsec_owner_str) - 1] == '.') { next_nsec_owner_str[strlen(next_nsec_owner_str) - 1] = '\0'; } status = ldns_str2rdf_b32_ext(&next_nsec_rdf, next_nsec_owner_str); ldns_rdf_deep_free(next_nsec_owner_label); LDNS_FREE(next_nsec_owner_str); if (!ldns_rr_set_rdf(ldns_rr_list_rr(nsec3_rrs, i), next_nsec_rdf, 4)) { /* todo: error */ } } } return status; } int qsort_rr_compare_nsec3(const void *a, const void *b) { const ldns_rr *rr1 = * (const ldns_rr **) a; const ldns_rr *rr2 = * (const ldns_rr **) b; if (rr1 == NULL && rr2 == NULL) { return 0; } if (rr1 == NULL) { return -1; } if (rr2 == NULL) { return 1; } return ldns_rdf_compare(ldns_rr_owner(rr1), ldns_rr_owner(rr2)); } void ldns_rr_list_sort_nsec3(ldns_rr_list *unsorted) { qsort(unsorted->_rrs, ldns_rr_list_rr_count(unsorted), sizeof(ldns_rr *), qsort_rr_compare_nsec3); } int ldns_dnssec_default_add_to_signatures( ATTR_UNUSED(ldns_rr *sig) , ATTR_UNUSED(void *n) ) { return LDNS_SIGNATURE_LEAVE_ADD_NEW; } int ldns_dnssec_default_leave_signatures( ATTR_UNUSED(ldns_rr *sig) , ATTR_UNUSED(void *n) ) { return LDNS_SIGNATURE_LEAVE_NO_ADD; } int ldns_dnssec_default_delete_signatures( ATTR_UNUSED(ldns_rr *sig) , ATTR_UNUSED(void *n) ) { return LDNS_SIGNATURE_REMOVE_NO_ADD; } int ldns_dnssec_default_replace_signatures( ATTR_UNUSED(ldns_rr *sig) , ATTR_UNUSED(void *n) ) { return LDNS_SIGNATURE_REMOVE_ADD_NEW; } #ifdef HAVE_SSL ldns_rdf * ldns_convert_dsa_rrsig_asn12rdf(const ldns_buffer *sig, const long sig_len) { ldns_rdf *sigdata_rdf; DSA_SIG *dsasig; unsigned char *dsasig_data = (unsigned char*)ldns_buffer_begin(sig); size_t byte_offset; dsasig = d2i_DSA_SIG(NULL, (const unsigned char **)&dsasig_data, sig_len); if (!dsasig) { DSA_SIG_free(dsasig); return NULL; } dsasig_data = LDNS_XMALLOC(unsigned char, 41); if(!dsasig_data) { DSA_SIG_free(dsasig); return NULL; } dsasig_data[0] = 0; byte_offset = (size_t) (20 - BN_num_bytes(dsasig->r)); if (byte_offset > 20) { DSA_SIG_free(dsasig); LDNS_FREE(dsasig_data); return NULL; } memset(&dsasig_data[1], 0, byte_offset); BN_bn2bin(dsasig->r, &dsasig_data[1 + byte_offset]); byte_offset = (size_t) (20 - BN_num_bytes(dsasig->s)); if (byte_offset > 20) { DSA_SIG_free(dsasig); LDNS_FREE(dsasig_data); return NULL; } memset(&dsasig_data[21], 0, byte_offset); BN_bn2bin(dsasig->s, &dsasig_data[21 + byte_offset]); sigdata_rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, 41, dsasig_data); if(!sigdata_rdf) { LDNS_FREE(dsasig_data); } DSA_SIG_free(dsasig); return sigdata_rdf; } ldns_status ldns_convert_dsa_rrsig_rdf2asn1(ldns_buffer *target_buffer, const ldns_rdf *sig_rdf) { /* the EVP api wants the DER encoding of the signature... */ BIGNUM *R, *S; DSA_SIG *dsasig; unsigned char *raw_sig = NULL; int raw_sig_len; if(ldns_rdf_size(sig_rdf) < 1 + 2*SHA_DIGEST_LENGTH) return LDNS_STATUS_SYNTAX_RDATA_ERR; /* extract the R and S field from the sig buffer */ R = BN_new(); if(!R) return LDNS_STATUS_MEM_ERR; (void) BN_bin2bn((unsigned char *) ldns_rdf_data(sig_rdf) + 1, SHA_DIGEST_LENGTH, R); S = BN_new(); if(!S) { BN_free(R); return LDNS_STATUS_MEM_ERR; } (void) BN_bin2bn((unsigned char *) ldns_rdf_data(sig_rdf) + 21, SHA_DIGEST_LENGTH, S); dsasig = DSA_SIG_new(); if (!dsasig) { BN_free(R); BN_free(S); return LDNS_STATUS_MEM_ERR; } dsasig->r = R; dsasig->s = S; raw_sig_len = i2d_DSA_SIG(dsasig, &raw_sig); if (raw_sig_len < 0) { DSA_SIG_free(dsasig); free(raw_sig); return LDNS_STATUS_SSL_ERR; } if (ldns_buffer_reserve(target_buffer, (size_t) raw_sig_len)) { ldns_buffer_write(target_buffer, raw_sig, (size_t)raw_sig_len); } DSA_SIG_free(dsasig); free(raw_sig); return ldns_buffer_status(target_buffer); } #ifdef USE_ECDSA #ifndef S_SPLINT_S ldns_rdf * ldns_convert_ecdsa_rrsig_asn12rdf(const ldns_buffer *sig, const long sig_len) { ECDSA_SIG* ecdsa_sig; unsigned char *data = (unsigned char*)ldns_buffer_begin(sig); ldns_rdf* rdf; ecdsa_sig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&data, sig_len); if(!ecdsa_sig) return NULL; /* "r | s". */ data = LDNS_XMALLOC(unsigned char, BN_num_bytes(ecdsa_sig->r) + BN_num_bytes(ecdsa_sig->s)); if(!data) { ECDSA_SIG_free(ecdsa_sig); return NULL; } BN_bn2bin(ecdsa_sig->r, data); BN_bn2bin(ecdsa_sig->s, data+BN_num_bytes(ecdsa_sig->r)); rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, (size_t)( BN_num_bytes(ecdsa_sig->r) + BN_num_bytes(ecdsa_sig->s)), data); ECDSA_SIG_free(ecdsa_sig); return rdf; } ldns_status ldns_convert_ecdsa_rrsig_rdf2asn1(ldns_buffer *target_buffer, const ldns_rdf *sig_rdf) { ECDSA_SIG* sig; int raw_sig_len; long bnsize = (long)ldns_rdf_size(sig_rdf) / 2; /* if too short, or not even length, do not bother */ if(bnsize < 16 || (size_t)bnsize*2 != ldns_rdf_size(sig_rdf)) return LDNS_STATUS_ERR; /* use the raw data to parse two evenly long BIGNUMs, "r | s". */ sig = ECDSA_SIG_new(); if(!sig) return LDNS_STATUS_MEM_ERR; sig->r = BN_bin2bn((const unsigned char*)ldns_rdf_data(sig_rdf), bnsize, sig->r); sig->s = BN_bin2bn((const unsigned char*)ldns_rdf_data(sig_rdf)+bnsize, bnsize, sig->s); if(!sig->r || !sig->s) { ECDSA_SIG_free(sig); return LDNS_STATUS_MEM_ERR; } raw_sig_len = i2d_ECDSA_SIG(sig, NULL); if (ldns_buffer_reserve(target_buffer, (size_t) raw_sig_len)) { unsigned char* pp = (unsigned char*) ldns_buffer_current(target_buffer); raw_sig_len = i2d_ECDSA_SIG(sig, &pp); ldns_buffer_skip(target_buffer, (ssize_t) raw_sig_len); } ECDSA_SIG_free(sig); return ldns_buffer_status(target_buffer); } #endif /* S_SPLINT_S */ #endif /* USE_ECDSA */ #endif /* HAVE_SSL */ Net-LDNS-0.75/src/ldns/dnssec_sign.c000644 000770 000024 00000113350 12471046240 017511 0ustar00calledstaff000000 000000 #include #include #include #include #include #include #ifdef HAVE_SSL /* this entire file is rather useless when you don't have * crypto... */ #include #include #include #include #include #endif /* HAVE_SSL */ ldns_rr * ldns_create_empty_rrsig(ldns_rr_list *rrset, ldns_key *current_key) { uint32_t orig_ttl; ldns_rr_class orig_class; time_t now; ldns_rr *current_sig; uint8_t label_count; ldns_rdf *signame; label_count = ldns_dname_label_count(ldns_rr_owner(ldns_rr_list_rr(rrset, 0))); /* RFC4035 2.2: not counting the leftmost label if it is a wildcard */ if(ldns_dname_is_wildcard(ldns_rr_owner(ldns_rr_list_rr(rrset, 0)))) label_count --; current_sig = ldns_rr_new_frm_type(LDNS_RR_TYPE_RRSIG); /* set the type on the new signature */ orig_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrset, 0)); orig_class = ldns_rr_get_class(ldns_rr_list_rr(rrset, 0)); ldns_rr_set_ttl(current_sig, orig_ttl); ldns_rr_set_class(current_sig, orig_class); ldns_rr_set_owner(current_sig, ldns_rdf_clone( ldns_rr_owner( ldns_rr_list_rr(rrset, 0)))); /* fill in what we know of the signature */ /* set the orig_ttl */ (void)ldns_rr_rrsig_set_origttl( current_sig, ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, orig_ttl)); /* the signers name */ signame = ldns_rdf_clone(ldns_key_pubkey_owner(current_key)); ldns_dname2canonical(signame); (void)ldns_rr_rrsig_set_signame( current_sig, signame); /* label count - get it from the first rr in the rr_list */ (void)ldns_rr_rrsig_set_labels( current_sig, ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, label_count)); /* inception, expiration */ now = time(NULL); if (ldns_key_inception(current_key) != 0) { (void)ldns_rr_rrsig_set_inception( current_sig, ldns_native2rdf_int32( LDNS_RDF_TYPE_TIME, ldns_key_inception(current_key))); } else { (void)ldns_rr_rrsig_set_inception( current_sig, ldns_native2rdf_int32(LDNS_RDF_TYPE_TIME, now)); } if (ldns_key_expiration(current_key) != 0) { (void)ldns_rr_rrsig_set_expiration( current_sig, ldns_native2rdf_int32( LDNS_RDF_TYPE_TIME, ldns_key_expiration(current_key))); } else { (void)ldns_rr_rrsig_set_expiration( current_sig, ldns_native2rdf_int32( LDNS_RDF_TYPE_TIME, now + LDNS_DEFAULT_EXP_TIME)); } (void)ldns_rr_rrsig_set_keytag( current_sig, ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, ldns_key_keytag(current_key))); (void)ldns_rr_rrsig_set_algorithm( current_sig, ldns_native2rdf_int8( LDNS_RDF_TYPE_ALG, ldns_key_algorithm(current_key))); (void)ldns_rr_rrsig_set_typecovered( current_sig, ldns_native2rdf_int16( LDNS_RDF_TYPE_TYPE, ldns_rr_get_type(ldns_rr_list_rr(rrset, 0)))); return current_sig; } #ifdef HAVE_SSL ldns_rdf * ldns_sign_public_buffer(ldns_buffer *sign_buf, ldns_key *current_key) { ldns_rdf *b64rdf = NULL; switch(ldns_key_algorithm(current_key)) { case LDNS_SIGN_DSA: case LDNS_SIGN_DSA_NSEC3: b64rdf = ldns_sign_public_evp( sign_buf, ldns_key_evp_key(current_key), EVP_dss1()); break; case LDNS_SIGN_RSASHA1: case LDNS_SIGN_RSASHA1_NSEC3: b64rdf = ldns_sign_public_evp( sign_buf, ldns_key_evp_key(current_key), EVP_sha1()); break; #ifdef USE_SHA2 case LDNS_SIGN_RSASHA256: b64rdf = ldns_sign_public_evp( sign_buf, ldns_key_evp_key(current_key), EVP_sha256()); break; case LDNS_SIGN_RSASHA512: b64rdf = ldns_sign_public_evp( sign_buf, ldns_key_evp_key(current_key), EVP_sha512()); break; #endif /* USE_SHA2 */ #ifdef USE_GOST case LDNS_SIGN_ECC_GOST: b64rdf = ldns_sign_public_evp( sign_buf, ldns_key_evp_key(current_key), EVP_get_digestbyname("md_gost94")); break; #endif /* USE_GOST */ #ifdef USE_ECDSA case LDNS_SIGN_ECDSAP256SHA256: b64rdf = ldns_sign_public_evp( sign_buf, ldns_key_evp_key(current_key), EVP_sha256()); break; case LDNS_SIGN_ECDSAP384SHA384: b64rdf = ldns_sign_public_evp( sign_buf, ldns_key_evp_key(current_key), EVP_sha384()); break; #endif case LDNS_SIGN_RSAMD5: b64rdf = ldns_sign_public_evp( sign_buf, ldns_key_evp_key(current_key), EVP_md5()); break; default: /* do _you_ know this alg? */ printf("unknown algorithm, "); printf("is the one used available on this system?\n"); break; } return b64rdf; } /** * use this function to sign with a public/private key alg * return the created signatures */ ldns_rr_list * ldns_sign_public(ldns_rr_list *rrset, ldns_key_list *keys) { ldns_rr_list *signatures; ldns_rr_list *rrset_clone; ldns_rr *current_sig; ldns_rdf *b64rdf; ldns_key *current_key; size_t key_count; uint16_t i; ldns_buffer *sign_buf; ldns_rdf *new_owner; if (!rrset || ldns_rr_list_rr_count(rrset) < 1 || !keys) { return NULL; } new_owner = NULL; signatures = ldns_rr_list_new(); /* prepare a signature and add all the know data * prepare the rrset. Sign this together. */ rrset_clone = ldns_rr_list_clone(rrset); if (!rrset_clone) { return NULL; } /* make it canonical */ for(i = 0; i < ldns_rr_list_rr_count(rrset_clone); i++) { ldns_rr_set_ttl(ldns_rr_list_rr(rrset_clone, i), ldns_rr_ttl(ldns_rr_list_rr(rrset, 0))); ldns_rr2canonical(ldns_rr_list_rr(rrset_clone, i)); } /* sort */ ldns_rr_list_sort(rrset_clone); for (key_count = 0; key_count < ldns_key_list_key_count(keys); key_count++) { if (!ldns_key_use(ldns_key_list_key(keys, key_count))) { continue; } sign_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!sign_buf) { ldns_rr_list_free(rrset_clone); ldns_rr_list_free(signatures); ldns_rdf_free(new_owner); return NULL; } b64rdf = NULL; current_key = ldns_key_list_key(keys, key_count); /* sign all RRs with keys that have ZSKbit, !SEPbit. sign DNSKEY RRs with keys that have ZSKbit&SEPbit */ if (ldns_key_flags(current_key) & LDNS_KEY_ZONE_KEY) { current_sig = ldns_create_empty_rrsig(rrset_clone, current_key); /* right now, we have: a key, a semi-sig and an rrset. For * which we can create the sig and base64 encode that and * add that to the signature */ if (ldns_rrsig2buffer_wire(sign_buf, current_sig) != LDNS_STATUS_OK) { ldns_buffer_free(sign_buf); /* ERROR */ ldns_rr_list_deep_free(rrset_clone); ldns_rr_free(current_sig); ldns_rr_list_deep_free(signatures); return NULL; } /* add the rrset in sign_buf */ if (ldns_rr_list2buffer_wire(sign_buf, rrset_clone) != LDNS_STATUS_OK) { ldns_buffer_free(sign_buf); ldns_rr_list_deep_free(rrset_clone); ldns_rr_free(current_sig); ldns_rr_list_deep_free(signatures); return NULL; } b64rdf = ldns_sign_public_buffer(sign_buf, current_key); if (!b64rdf) { /* signing went wrong */ ldns_rr_list_deep_free(rrset_clone); ldns_rr_free(current_sig); ldns_rr_list_deep_free(signatures); return NULL; } ldns_rr_rrsig_set_sig(current_sig, b64rdf); /* push the signature to the signatures list */ ldns_rr_list_push_rr(signatures, current_sig); } ldns_buffer_free(sign_buf); /* restart for the next key */ } ldns_rr_list_deep_free(rrset_clone); return signatures; } /** * Sign data with DSA * * \param[in] to_sign The ldns_buffer containing raw data that is * to be signed * \param[in] key The DSA key structure to sign with * \return ldns_rdf for the RRSIG ldns_rr */ ldns_rdf * ldns_sign_public_dsa(ldns_buffer *to_sign, DSA *key) { unsigned char *sha1_hash; ldns_rdf *sigdata_rdf; ldns_buffer *b64sig; DSA_SIG *sig; uint8_t *data; size_t pad; b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!b64sig) { return NULL; } sha1_hash = SHA1((unsigned char*)ldns_buffer_begin(to_sign), ldns_buffer_position(to_sign), NULL); if (!sha1_hash) { ldns_buffer_free(b64sig); return NULL; } sig = DSA_do_sign(sha1_hash, SHA_DIGEST_LENGTH, key); if(!sig) { ldns_buffer_free(b64sig); return NULL; } data = LDNS_XMALLOC(uint8_t, 1 + 2 * SHA_DIGEST_LENGTH); if(!data) { ldns_buffer_free(b64sig); DSA_SIG_free(sig); return NULL; } data[0] = 1; pad = 20 - (size_t) BN_num_bytes(sig->r); if (pad > 0) { memset(data + 1, 0, pad); } BN_bn2bin(sig->r, (unsigned char *) (data + 1) + pad); pad = 20 - (size_t) BN_num_bytes(sig->s); if (pad > 0) { memset(data + 1 + SHA_DIGEST_LENGTH, 0, pad); } BN_bn2bin(sig->s, (unsigned char *) (data + 1 + SHA_DIGEST_LENGTH + pad)); sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, 1 + 2 * SHA_DIGEST_LENGTH, data); ldns_buffer_free(b64sig); LDNS_FREE(data); DSA_SIG_free(sig); return sigdata_rdf; } #ifdef USE_ECDSA #ifndef S_SPLINT_S static int ldns_pkey_is_ecdsa(EVP_PKEY* pkey) { EC_KEY* ec; const EC_GROUP* g; if(EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) return 0; ec = EVP_PKEY_get1_EC_KEY(pkey); g = EC_KEY_get0_group(ec); if(!g) { EC_KEY_free(ec); return 0; } if(EC_GROUP_get_curve_name(g) == NID_secp224r1 || EC_GROUP_get_curve_name(g) == NID_X9_62_prime256v1 || EC_GROUP_get_curve_name(g) == NID_secp384r1) { EC_KEY_free(ec); return 1; } /* downref the eckey, the original is still inside the pkey */ EC_KEY_free(ec); return 0; } #endif /* splint */ #endif /* USE_ECDSA */ ldns_rdf * ldns_sign_public_evp(ldns_buffer *to_sign, EVP_PKEY *key, const EVP_MD *digest_type) { unsigned int siglen; ldns_rdf *sigdata_rdf; ldns_buffer *b64sig; EVP_MD_CTX ctx; const EVP_MD *md_type; int r; siglen = 0; b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!b64sig) { return NULL; } /* initializes a signing context */ md_type = digest_type; if(!md_type) { /* unknown message difest */ ldns_buffer_free(b64sig); return NULL; } EVP_MD_CTX_init(&ctx); r = EVP_SignInit(&ctx, md_type); if(r == 1) { r = EVP_SignUpdate(&ctx, (unsigned char*) ldns_buffer_begin(to_sign), ldns_buffer_position(to_sign)); } else { ldns_buffer_free(b64sig); return NULL; } if(r == 1) { r = EVP_SignFinal(&ctx, (unsigned char*) ldns_buffer_begin(b64sig), &siglen, key); } else { ldns_buffer_free(b64sig); return NULL; } if(r != 1) { ldns_buffer_free(b64sig); return NULL; } /* unfortunately, OpenSSL output is differenct from DNS DSA format */ #ifndef S_SPLINT_S if (EVP_PKEY_type(key->type) == EVP_PKEY_DSA) { sigdata_rdf = ldns_convert_dsa_rrsig_asn12rdf(b64sig, siglen); #ifdef USE_ECDSA } else if(EVP_PKEY_type(key->type) == EVP_PKEY_EC && ldns_pkey_is_ecdsa(key)) { sigdata_rdf = ldns_convert_ecdsa_rrsig_asn12rdf(b64sig, siglen); #endif } else { /* ok output for other types is the same */ sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen, ldns_buffer_begin(b64sig)); } #endif /* splint */ ldns_buffer_free(b64sig); EVP_MD_CTX_cleanup(&ctx); return sigdata_rdf; } ldns_rdf * ldns_sign_public_rsasha1(ldns_buffer *to_sign, RSA *key) { unsigned char *sha1_hash; unsigned int siglen; ldns_rdf *sigdata_rdf; ldns_buffer *b64sig; int result; siglen = 0; b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!b64sig) { return NULL; } sha1_hash = SHA1((unsigned char*)ldns_buffer_begin(to_sign), ldns_buffer_position(to_sign), NULL); if (!sha1_hash) { ldns_buffer_free(b64sig); return NULL; } result = RSA_sign(NID_sha1, sha1_hash, SHA_DIGEST_LENGTH, (unsigned char*)ldns_buffer_begin(b64sig), &siglen, key); if (result != 1) { ldns_buffer_free(b64sig); return NULL; } sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen, ldns_buffer_begin(b64sig)); ldns_buffer_free(b64sig); /* can't free this buffer ?? */ return sigdata_rdf; } ldns_rdf * ldns_sign_public_rsamd5(ldns_buffer *to_sign, RSA *key) { unsigned char *md5_hash; unsigned int siglen; ldns_rdf *sigdata_rdf; ldns_buffer *b64sig; b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!b64sig) { return NULL; } md5_hash = MD5((unsigned char*)ldns_buffer_begin(to_sign), ldns_buffer_position(to_sign), NULL); if (!md5_hash) { ldns_buffer_free(b64sig); return NULL; } RSA_sign(NID_md5, md5_hash, MD5_DIGEST_LENGTH, (unsigned char*)ldns_buffer_begin(b64sig), &siglen, key); sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen, ldns_buffer_begin(b64sig)); ldns_buffer_free(b64sig); return sigdata_rdf; } #endif /* HAVE_SSL */ /** * Pushes all rrs from the rrsets of type A and AAAA on gluelist. */ static ldns_status ldns_dnssec_addresses_on_glue_list( ldns_dnssec_rrsets *cur_rrset, ldns_rr_list *glue_list) { ldns_dnssec_rrs *cur_rrs; while (cur_rrset) { if (cur_rrset->type == LDNS_RR_TYPE_A || cur_rrset->type == LDNS_RR_TYPE_AAAA) { for (cur_rrs = cur_rrset->rrs; cur_rrs; cur_rrs = cur_rrs->next) { if (cur_rrs->rr) { if (!ldns_rr_list_push_rr(glue_list, cur_rrs->rr)) { return LDNS_STATUS_MEM_ERR; /* ldns_rr_list_push_rr() * returns false when unable * to increase the capacity * of the ldsn_rr_list */ } } } } cur_rrset = cur_rrset->next; } return LDNS_STATUS_OK; } /** * Marks the names in the zone that are occluded. Those names will be skipped * when walking the tree with the ldns_dnssec_name_node_next_nonglue() * function. But watch out! Names that are partially occluded (like glue with * the same name as the delegation) will not be marked and should specifically * be taken into account separately. * * When glue_list is given (not NULL), in the process of marking the names, all * glue resource records will be pushed to that list, even glue at delegation names. * * \param[in] zone the zone in which to mark the names * \param[in] glue_list the list to which to push the glue rrs * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_mark_and_get_glue(ldns_dnssec_zone *zone, ldns_rr_list *glue_list) { ldns_rbnode_t *node; ldns_dnssec_name *name; ldns_rdf *owner; ldns_rdf *cut = NULL; /* keeps track of zone cuts */ /* When the cut is caused by a delegation, below_delegation will be 1. * When caused by a DNAME, below_delegation will be 0. */ int below_delegation = -1; /* init suppresses comiler warning */ ldns_status s; if (!zone || !zone->names) { return LDNS_STATUS_NULL; } for (node = ldns_rbtree_first(zone->names); node != LDNS_RBTREE_NULL; node = ldns_rbtree_next(node)) { name = (ldns_dnssec_name *) node->data; owner = ldns_dnssec_name_name(name); if (cut) { /* The previous node was a zone cut, or a subdomain * below a zone cut. Is this node (still) a subdomain * below the cut? Then the name is occluded. Unless * the name contains a SOA, after which we are * authoritative again. * * FIXME! If there are labels in between the SOA and * the cut, going from the authoritative space (below * the SOA) up into occluded space again, will not be * detected with the contruct below! */ if (ldns_dname_is_subdomain(owner, cut) && !ldns_dnssec_rrsets_contains_type( name->rrsets, LDNS_RR_TYPE_SOA)) { if (below_delegation && glue_list) { s = ldns_dnssec_addresses_on_glue_list( name->rrsets, glue_list); if (s != LDNS_STATUS_OK) { return s; } } name->is_glue = true; /* Mark occluded name! */ continue; } else { cut = NULL; } } /* The node is not below a zone cut. Is it a zone cut itself? * Everything below a SOA is authoritative of course; Except * when the name also contains a DNAME :). */ if (ldns_dnssec_rrsets_contains_type( name->rrsets, LDNS_RR_TYPE_NS) && !ldns_dnssec_rrsets_contains_type( name->rrsets, LDNS_RR_TYPE_SOA)) { cut = owner; below_delegation = 1; if (glue_list) { /* record glue on the zone cut */ s = ldns_dnssec_addresses_on_glue_list( name->rrsets, glue_list); if (s != LDNS_STATUS_OK) { return s; } } } else if (ldns_dnssec_rrsets_contains_type( name->rrsets, LDNS_RR_TYPE_DNAME)) { cut = owner; below_delegation = 0; } } return LDNS_STATUS_OK; } /** * Marks the names in the zone that are occluded. Those names will be skipped * when walking the tree with the ldns_dnssec_name_node_next_nonglue() * function. But watch out! Names that are partially occluded (like glue with * the same name as the delegation) will not be marked and should specifically * be taken into account separately. * * \param[in] zone the zone in which to mark the names * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone) { return ldns_dnssec_zone_mark_and_get_glue(zone, NULL); } ldns_rbnode_t * ldns_dnssec_name_node_next_nonglue(ldns_rbnode_t *node) { ldns_rbnode_t *next_node = NULL; ldns_dnssec_name *next_name = NULL; bool done = false; if (node == LDNS_RBTREE_NULL) { return NULL; } next_node = node; while (!done) { if (next_node == LDNS_RBTREE_NULL) { return NULL; } else { next_name = (ldns_dnssec_name *)next_node->data; if (!next_name->is_glue) { done = true; } else { next_node = ldns_rbtree_next(next_node); } } } return next_node; } ldns_status ldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs) { ldns_rbnode_t *first_node, *cur_node, *next_node; ldns_dnssec_name *cur_name, *next_name; ldns_rr *nsec_rr; uint32_t nsec_ttl; ldns_dnssec_rrsets *soa; /* the TTL of NSEC rrs should be set to the minimum TTL of * the zone SOA (RFC4035 Section 2.3) */ soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA); /* did the caller actually set it? if not, * fall back to default ttl */ if (soa && soa->rrs && soa->rrs->rr && (ldns_rr_rdf(soa->rrs->rr, 6) != NULL)) { nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(soa->rrs->rr, 6)); } else { nsec_ttl = LDNS_DEFAULT_TTL; } first_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_first(zone->names)); cur_node = first_node; if (cur_node) { next_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(cur_node)); } else { next_node = NULL; } while (cur_node && next_node) { cur_name = (ldns_dnssec_name *)cur_node->data; next_name = (ldns_dnssec_name *)next_node->data; nsec_rr = ldns_dnssec_create_nsec(cur_name, next_name, LDNS_RR_TYPE_NSEC); ldns_rr_set_ttl(nsec_rr, nsec_ttl); if(ldns_dnssec_name_add_rr(cur_name, nsec_rr)!=LDNS_STATUS_OK){ ldns_rr_free(nsec_rr); return LDNS_STATUS_ERR; } ldns_rr_list_push_rr(new_rrs, nsec_rr); cur_node = next_node; if (cur_node) { next_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(cur_node)); } } if (cur_node && !next_node) { cur_name = (ldns_dnssec_name *)cur_node->data; next_name = (ldns_dnssec_name *)first_node->data; nsec_rr = ldns_dnssec_create_nsec(cur_name, next_name, LDNS_RR_TYPE_NSEC); ldns_rr_set_ttl(nsec_rr, nsec_ttl); if(ldns_dnssec_name_add_rr(cur_name, nsec_rr)!=LDNS_STATUS_OK){ ldns_rr_free(nsec_rr); return LDNS_STATUS_ERR; } ldns_rr_list_push_rr(new_rrs, nsec_rr); } else { printf("error\n"); } return LDNS_STATUS_OK; } #ifdef HAVE_SSL static void ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) { (void) arg; LDNS_FREE(node); } static ldns_status ldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt, ldns_rbtree_t **map) { ldns_rbnode_t *first_name_node; ldns_rbnode_t *current_name_node; ldns_dnssec_name *current_name; ldns_status result = LDNS_STATUS_OK; ldns_rr *nsec_rr; ldns_rr_list *nsec3_list; uint32_t nsec_ttl; ldns_dnssec_rrsets *soa; ldns_rbnode_t *hashmap_node; if (!zone || !new_rrs || !zone->names) { return LDNS_STATUS_ERR; } /* the TTL of NSEC rrs should be set to the minimum TTL of * the zone SOA (RFC4035 Section 2.3) */ soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA); /* did the caller actually set it? if not, * fall back to default ttl */ if (soa && soa->rrs && soa->rrs->rr && ldns_rr_rdf(soa->rrs->rr, 6) != NULL) { nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(soa->rrs->rr, 6)); } else { nsec_ttl = LDNS_DEFAULT_TTL; } if (zone->hashed_names) { ldns_traverse_postorder(zone->hashed_names, ldns_hashed_names_node_free, NULL); LDNS_FREE(zone->hashed_names); } zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v); if (zone->hashed_names && map) { *map = zone->hashed_names; } first_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_first(zone->names)); current_name_node = first_name_node; while (current_name_node && current_name_node != LDNS_RBTREE_NULL && result == LDNS_STATUS_OK) { current_name = (ldns_dnssec_name *) current_name_node->data; nsec_rr = ldns_dnssec_create_nsec3(current_name, NULL, zone->soa->name, algorithm, flags, iterations, salt_length, salt); /* by default, our nsec based generator adds rrsigs * remove the bitmap for empty nonterminals */ if (!current_name->rrsets) { ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr)); } ldns_rr_set_ttl(nsec_rr, nsec_ttl); result = ldns_dnssec_name_add_rr(current_name, nsec_rr); ldns_rr_list_push_rr(new_rrs, nsec_rr); if (ldns_rr_owner(nsec_rr)) { hashmap_node = LDNS_MALLOC(ldns_rbnode_t); if (hashmap_node == NULL) { return LDNS_STATUS_MEM_ERR; } current_name->hashed_name = ldns_dname_label(ldns_rr_owner(nsec_rr), 0); if (current_name->hashed_name == NULL) { LDNS_FREE(hashmap_node); return LDNS_STATUS_MEM_ERR; } hashmap_node->key = current_name->hashed_name; hashmap_node->data = current_name; if (! ldns_rbtree_insert(zone->hashed_names , hashmap_node)) { LDNS_FREE(hashmap_node); } } current_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(current_name_node)); } if (result != LDNS_STATUS_OK) { return result; } /* Make sorted list of nsec3s (via zone->hashed_names) */ nsec3_list = ldns_rr_list_new(); if (nsec3_list == NULL) { return LDNS_STATUS_MEM_ERR; } for ( hashmap_node = ldns_rbtree_first(zone->hashed_names) ; hashmap_node != LDNS_RBTREE_NULL ; hashmap_node = ldns_rbtree_next(hashmap_node) ) { current_name = (ldns_dnssec_name *) hashmap_node->data; nsec_rr = ((ldns_dnssec_name *) hashmap_node->data)->nsec; if (nsec_rr) { ldns_rr_list_push_rr(nsec3_list, nsec_rr); } } result = ldns_dnssec_chain_nsec3_list(nsec3_list); ldns_rr_list_free(nsec3_list); return result; } ldns_status ldns_dnssec_zone_create_nsec3s(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt) { return ldns_dnssec_zone_create_nsec3s_mkmap(zone, new_rrs, algorithm, flags, iterations, salt_length, salt, NULL); } #endif /* HAVE_SSL */ ldns_dnssec_rrs * ldns_dnssec_remove_signatures( ldns_dnssec_rrs *signatures , ATTR_UNUSED(ldns_key_list *key_list) , int (*func)(ldns_rr *, void *) , void *arg ) { ldns_dnssec_rrs *base_rrs = signatures; ldns_dnssec_rrs *cur_rr = base_rrs; ldns_dnssec_rrs *prev_rr = NULL; ldns_dnssec_rrs *next_rr; uint16_t keytag; size_t i; if (!cur_rr) { switch(func(NULL, arg)) { case LDNS_SIGNATURE_LEAVE_ADD_NEW: case LDNS_SIGNATURE_REMOVE_ADD_NEW: break; case LDNS_SIGNATURE_LEAVE_NO_ADD: case LDNS_SIGNATURE_REMOVE_NO_ADD: ldns_key_list_set_use(key_list, false); break; default: #ifdef STDERR_MSGS fprintf(stderr, "[XX] unknown return value from callback\n"); #endif break; } return NULL; } (void)func(cur_rr->rr, arg); while (cur_rr) { next_rr = cur_rr->next; switch (func(cur_rr->rr, arg)) { case LDNS_SIGNATURE_LEAVE_ADD_NEW: prev_rr = cur_rr; break; case LDNS_SIGNATURE_LEAVE_NO_ADD: keytag = ldns_rdf2native_int16( ldns_rr_rrsig_keytag(cur_rr->rr)); for (i = 0; i < ldns_key_list_key_count(key_list); i++) { if (ldns_key_keytag(ldns_key_list_key(key_list, i)) == keytag) { ldns_key_set_use(ldns_key_list_key(key_list, i), false); } } prev_rr = cur_rr; break; case LDNS_SIGNATURE_REMOVE_NO_ADD: keytag = ldns_rdf2native_int16( ldns_rr_rrsig_keytag(cur_rr->rr)); for (i = 0; i < ldns_key_list_key_count(key_list); i++) { if (ldns_key_keytag(ldns_key_list_key(key_list, i)) == keytag) { ldns_key_set_use(ldns_key_list_key(key_list, i), false); } } if (prev_rr) { prev_rr->next = next_rr; } else { base_rrs = next_rr; } LDNS_FREE(cur_rr); break; case LDNS_SIGNATURE_REMOVE_ADD_NEW: if (prev_rr) { prev_rr->next = next_rr; } else { base_rrs = next_rr; } LDNS_FREE(cur_rr); break; default: #ifdef STDERR_MSGS fprintf(stderr, "[XX] unknown return value from callback\n"); #endif break; } cur_rr = next_rr; } return base_rrs; } #ifdef HAVE_SSL ldns_status ldns_dnssec_zone_create_rrsigs(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void*), void *arg) { return ldns_dnssec_zone_create_rrsigs_flg(zone, new_rrs, key_list, func, arg, 0); } /** If there are KSKs use only them and mark ZSKs unused */ static void ldns_key_list_filter_for_dnskey(ldns_key_list *key_list) { int saw_ksk = 0; size_t i; for(i=0; inames); while (cur_node != LDNS_RBTREE_NULL) { cur_name = (ldns_dnssec_name *) cur_node->data; if (!cur_name->is_glue) { on_delegation_point = ldns_dnssec_rrsets_contains_type( cur_name->rrsets, LDNS_RR_TYPE_NS) && !ldns_dnssec_rrsets_contains_type( cur_name->rrsets, LDNS_RR_TYPE_SOA); cur_rrset = cur_name->rrsets; while (cur_rrset) { /* reset keys to use */ ldns_key_list_set_use(key_list, true); /* walk through old sigs, remove the old, and mark which keys (not) to use) */ cur_rrset->signatures = ldns_dnssec_remove_signatures(cur_rrset->signatures, key_list, func, arg); if(!(flags&LDNS_SIGN_DNSKEY_WITH_ZSK) && cur_rrset->type == LDNS_RR_TYPE_DNSKEY) ldns_key_list_filter_for_dnskey(key_list); if(cur_rrset->type != LDNS_RR_TYPE_DNSKEY) ldns_key_list_filter_for_non_dnskey(key_list); /* TODO: just set count to zero? */ rr_list = ldns_rr_list_new(); cur_rr = cur_rrset->rrs; while (cur_rr) { ldns_rr_list_push_rr(rr_list, cur_rr->rr); cur_rr = cur_rr->next; } /* only sign non-delegation RRsets */ /* (glue should have been marked earlier, * except on the delegation points itself) */ if (!on_delegation_point || ldns_rr_list_type(rr_list) == LDNS_RR_TYPE_DS || ldns_rr_list_type(rr_list) == LDNS_RR_TYPE_NSEC || ldns_rr_list_type(rr_list) == LDNS_RR_TYPE_NSEC3) { siglist = ldns_sign_public(rr_list, key_list); for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) { if (cur_rrset->signatures) { result = ldns_dnssec_rrs_add_rr(cur_rrset->signatures, ldns_rr_list_rr(siglist, i)); } else { cur_rrset->signatures = ldns_dnssec_rrs_new(); cur_rrset->signatures->rr = ldns_rr_list_rr(siglist, i); } if (new_rrs) { ldns_rr_list_push_rr(new_rrs, ldns_rr_list_rr(siglist, i)); } } ldns_rr_list_free(siglist); } ldns_rr_list_free(rr_list); cur_rrset = cur_rrset->next; } /* sign the nsec */ ldns_key_list_set_use(key_list, true); cur_name->nsec_signatures = ldns_dnssec_remove_signatures(cur_name->nsec_signatures, key_list, func, arg); ldns_key_list_filter_for_non_dnskey(key_list); rr_list = ldns_rr_list_new(); ldns_rr_list_push_rr(rr_list, cur_name->nsec); siglist = ldns_sign_public(rr_list, key_list); for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) { if (cur_name->nsec_signatures) { result = ldns_dnssec_rrs_add_rr(cur_name->nsec_signatures, ldns_rr_list_rr(siglist, i)); } else { cur_name->nsec_signatures = ldns_dnssec_rrs_new(); cur_name->nsec_signatures->rr = ldns_rr_list_rr(siglist, i); } if (new_rrs) { ldns_rr_list_push_rr(new_rrs, ldns_rr_list_rr(siglist, i)); } } ldns_rr_list_free(siglist); ldns_rr_list_free(rr_list); } cur_node = ldns_rbtree_next(cur_node); } ldns_rr_list_deep_free(pubkey_list); return result; } ldns_status ldns_dnssec_zone_sign(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg) { return ldns_dnssec_zone_sign_flg(zone, new_rrs, key_list, func, arg, 0); } ldns_status ldns_dnssec_zone_sign_flg(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg, int flags) { ldns_status result = LDNS_STATUS_OK; if (!zone || !new_rrs || !key_list) { return LDNS_STATUS_ERR; } /* zone is already sorted */ result = ldns_dnssec_zone_mark_glue(zone); if (result != LDNS_STATUS_OK) { return result; } /* check whether we need to add nsecs */ if (zone->names && !((ldns_dnssec_name *)zone->names->root->data)->nsec) { result = ldns_dnssec_zone_create_nsecs(zone, new_rrs); if (result != LDNS_STATUS_OK) { return result; } } result = ldns_dnssec_zone_create_rrsigs_flg(zone, new_rrs, key_list, func, arg, flags); return result; } ldns_status ldns_dnssec_zone_sign_nsec3(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt) { return ldns_dnssec_zone_sign_nsec3_flg_mkmap(zone, new_rrs, key_list, func, arg, algorithm, flags, iterations, salt_length, salt, 0, NULL); } ldns_status ldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt, int signflags, ldns_rbtree_t **map) { ldns_rr *nsec3, *nsec3param; ldns_status result = LDNS_STATUS_OK; /* zone is already sorted */ result = ldns_dnssec_zone_mark_glue(zone); if (result != LDNS_STATUS_OK) { return result; } /* TODO if there are already nsec3s presents and their * parameters are the same as these, we don't have to recreate */ if (zone->names) { /* add empty nonterminals */ result = ldns_dnssec_zone_add_empty_nonterminals(zone); if (result != LDNS_STATUS_OK) { return result; } nsec3 = ((ldns_dnssec_name *)zone->names->root->data)->nsec; if (nsec3 && ldns_rr_get_type(nsec3) == LDNS_RR_TYPE_NSEC3) { /* no need to recreate */ } else { if (!ldns_dnssec_zone_find_rrset(zone, zone->soa->name, LDNS_RR_TYPE_NSEC3PARAM)) { /* create and add the nsec3param rr */ nsec3param = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAM); ldns_rr_set_owner(nsec3param, ldns_rdf_clone(zone->soa->name)); ldns_nsec3_add_param_rdfs(nsec3param, algorithm, flags, iterations, salt_length, salt); /* always set bit 7 of the flags to zero, according to * rfc5155 section 11. The bits are counted from right to left, * so bit 7 in rfc5155 is bit 0 in ldns */ ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(nsec3param, 1)), 0, 0); result = ldns_dnssec_zone_add_rr(zone, nsec3param); if (result != LDNS_STATUS_OK) { return result; } ldns_rr_list_push_rr(new_rrs, nsec3param); } result = ldns_dnssec_zone_create_nsec3s_mkmap(zone, new_rrs, algorithm, flags, iterations, salt_length, salt, map); if (result != LDNS_STATUS_OK) { return result; } } result = ldns_dnssec_zone_create_rrsigs_flg(zone, new_rrs, key_list, func, arg, signflags); } return result; } ldns_status ldns_dnssec_zone_sign_nsec3_flg(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt, int signflags) { return ldns_dnssec_zone_sign_nsec3_flg_mkmap(zone, new_rrs, key_list, func, arg, algorithm, flags, iterations, salt_length, salt, signflags, NULL); } ldns_zone * ldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list) { ldns_dnssec_zone *dnssec_zone; ldns_zone *signed_zone; ldns_rr_list *new_rrs; size_t i; signed_zone = ldns_zone_new(); dnssec_zone = ldns_dnssec_zone_new(); (void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(zone)); ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone))); for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) { (void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_rr_list_rr(ldns_zone_rrs(zone), i)); ldns_zone_push_rr(signed_zone, ldns_rr_clone(ldns_rr_list_rr(ldns_zone_rrs(zone), i))); } new_rrs = ldns_rr_list_new(); (void) ldns_dnssec_zone_sign(dnssec_zone, new_rrs, key_list, ldns_dnssec_default_replace_signatures, NULL); for (i = 0; i < ldns_rr_list_rr_count(new_rrs); i++) { ldns_rr_list_push_rr(ldns_zone_rrs(signed_zone), ldns_rr_clone(ldns_rr_list_rr(new_rrs, i))); } ldns_rr_list_deep_free(new_rrs); ldns_dnssec_zone_free(dnssec_zone); return signed_zone; } ldns_zone * ldns_zone_sign_nsec3(ldns_zone *zone, ldns_key_list *key_list, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt) { ldns_dnssec_zone *dnssec_zone; ldns_zone *signed_zone; ldns_rr_list *new_rrs; size_t i; signed_zone = ldns_zone_new(); dnssec_zone = ldns_dnssec_zone_new(); (void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(zone)); ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone))); for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) { (void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_rr_list_rr(ldns_zone_rrs(zone), i)); ldns_zone_push_rr(signed_zone, ldns_rr_clone(ldns_rr_list_rr(ldns_zone_rrs(zone), i))); } new_rrs = ldns_rr_list_new(); (void) ldns_dnssec_zone_sign_nsec3(dnssec_zone, new_rrs, key_list, ldns_dnssec_default_replace_signatures, NULL, algorithm, flags, iterations, salt_length, salt); for (i = 0; i < ldns_rr_list_rr_count(new_rrs); i++) { ldns_rr_list_push_rr(ldns_zone_rrs(signed_zone), ldns_rr_clone(ldns_rr_list_rr(new_rrs, i))); } ldns_rr_list_deep_free(new_rrs); ldns_dnssec_zone_free(dnssec_zone); return signed_zone; } #endif /* HAVE_SSL */ Net-LDNS-0.75/src/ldns/dnssec_verify.c000644 000770 000024 00000214261 12471046240 020060 0ustar00calledstaff000000 000000 #include #include #include #include #ifdef HAVE_SSL /* this entire file is rather useless when you don't have * crypto... */ #include #include #include #include #include ldns_dnssec_data_chain * ldns_dnssec_data_chain_new(void) { ldns_dnssec_data_chain *nc = LDNS_CALLOC(ldns_dnssec_data_chain, 1); if(!nc) return NULL; /* * not needed anymore because CALLOC initalizes everything to zero. nc->rrset = NULL; nc->parent_type = 0; nc->parent = NULL; nc->signatures = NULL; nc->packet_rcode = 0; nc->packet_qtype = 0; nc->packet_nodata = false; */ return nc; } void ldns_dnssec_data_chain_free(ldns_dnssec_data_chain *chain) { LDNS_FREE(chain); } void ldns_dnssec_data_chain_deep_free(ldns_dnssec_data_chain *chain) { ldns_rr_list_deep_free(chain->rrset); ldns_rr_list_deep_free(chain->signatures); if (chain->parent) { ldns_dnssec_data_chain_deep_free(chain->parent); } LDNS_FREE(chain); } void ldns_dnssec_data_chain_print_fmt(FILE *out, const ldns_output_format *fmt, const ldns_dnssec_data_chain *chain) { ldns_lookup_table *rcode; const ldns_rr_descriptor *rr_descriptor; if (chain) { ldns_dnssec_data_chain_print_fmt(out, fmt, chain->parent); if (ldns_rr_list_rr_count(chain->rrset) > 0) { rcode = ldns_lookup_by_id(ldns_rcodes, (int) chain->packet_rcode); if (rcode) { fprintf(out, ";; rcode: %s\n", rcode->name); } rr_descriptor = ldns_rr_descript(chain->packet_qtype); if (rr_descriptor && rr_descriptor->_name) { fprintf(out, ";; qtype: %s\n", rr_descriptor->_name); } else if (chain->packet_qtype != 0) { fprintf(out, "TYPE%u", chain->packet_qtype); } if (chain->packet_nodata) { fprintf(out, ";; NODATA response\n"); } fprintf(out, "rrset:\n"); ldns_rr_list_print_fmt(out, fmt, chain->rrset); fprintf(out, "sigs:\n"); ldns_rr_list_print_fmt(out, fmt, chain->signatures); fprintf(out, "---\n"); } else { fprintf(out, "\n"); } } } void ldns_dnssec_data_chain_print(FILE *out, const ldns_dnssec_data_chain *chain) { ldns_dnssec_data_chain_print_fmt( out, ldns_output_format_default, chain); } static void ldns_dnssec_build_data_chain_dnskey(ldns_resolver *res, uint16_t qflags, const ldns_pkt *pkt, ldns_rr_list *signatures, ldns_dnssec_data_chain *new_chain, ldns_rdf *key_name, ldns_rr_class c) { ldns_rr_list *keys; ldns_pkt *my_pkt; if (signatures && ldns_rr_list_rr_count(signatures) > 0) { new_chain->signatures = ldns_rr_list_clone(signatures); new_chain->parent_type = 0; keys = ldns_pkt_rr_list_by_name_and_type( pkt, key_name, LDNS_RR_TYPE_DNSKEY, LDNS_SECTION_ANY_NOQUESTION ); if (!keys) { my_pkt = ldns_resolver_query(res, key_name, LDNS_RR_TYPE_DNSKEY, c, qflags); if (my_pkt) { keys = ldns_pkt_rr_list_by_name_and_type( my_pkt, key_name, LDNS_RR_TYPE_DNSKEY, LDNS_SECTION_ANY_NOQUESTION ); new_chain->parent = ldns_dnssec_build_data_chain(res, qflags, keys, my_pkt, NULL); new_chain->parent->packet_qtype = LDNS_RR_TYPE_DNSKEY; ldns_pkt_free(my_pkt); } } else { new_chain->parent = ldns_dnssec_build_data_chain(res, qflags, keys, pkt, NULL); new_chain->parent->packet_qtype = LDNS_RR_TYPE_DNSKEY; } ldns_rr_list_deep_free(keys); } } static void ldns_dnssec_build_data_chain_other(ldns_resolver *res, uint16_t qflags, ldns_dnssec_data_chain *new_chain, ldns_rdf *key_name, ldns_rr_class c, ldns_rr_list *dss) { /* 'self-signed', parent is a DS */ /* okay, either we have other keys signing the current one, * or the current * one should have a DS record in the parent zone. * How do we find this out? Try both? * * request DNSKEYS for current zone, * add all signatures to current level */ ldns_pkt *my_pkt; ldns_rr_list *signatures2; new_chain->parent_type = 1; my_pkt = ldns_resolver_query(res, key_name, LDNS_RR_TYPE_DS, c, qflags); if (my_pkt) { dss = ldns_pkt_rr_list_by_name_and_type(my_pkt, key_name, LDNS_RR_TYPE_DS, LDNS_SECTION_ANY_NOQUESTION ); if (dss) { new_chain->parent = ldns_dnssec_build_data_chain(res, qflags, dss, my_pkt, NULL); new_chain->parent->packet_qtype = LDNS_RR_TYPE_DS; ldns_rr_list_deep_free(dss); } ldns_pkt_free(my_pkt); } my_pkt = ldns_resolver_query(res, key_name, LDNS_RR_TYPE_DNSKEY, c, qflags); if (my_pkt) { signatures2 = ldns_pkt_rr_list_by_name_and_type(my_pkt, key_name, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANSWER); if (signatures2) { if (new_chain->signatures) { printf("There were already sigs!\n"); ldns_rr_list_deep_free(new_chain->signatures); printf("replacing the old sigs\n"); } new_chain->signatures = signatures2; } ldns_pkt_free(my_pkt); } } static ldns_dnssec_data_chain * ldns_dnssec_build_data_chain_nokeyname(ldns_resolver *res, uint16_t qflags, ldns_rr *orig_rr, const ldns_rr_list *rrset, ldns_dnssec_data_chain *new_chain) { ldns_rdf *possible_parent_name; ldns_pkt *my_pkt; /* apparently we were not able to find a signing key, so we assume the chain ends here */ /* try parents for auth denial of DS */ if (orig_rr) { possible_parent_name = ldns_rr_owner(orig_rr); } else if (rrset && ldns_rr_list_rr_count(rrset) > 0) { possible_parent_name = ldns_rr_owner(ldns_rr_list_rr(rrset, 0)); } else { /* no information to go on, give up */ return new_chain; } my_pkt = ldns_resolver_query(res, possible_parent_name, LDNS_RR_TYPE_DS, LDNS_RR_CLASS_IN, qflags); if (!my_pkt) { return new_chain; } if (ldns_pkt_ancount(my_pkt) > 0) { /* add error, no sigs but DS in parent */ /*ldns_pkt_print(stdout, my_pkt);*/ ldns_pkt_free(my_pkt); } else { /* are there signatures? */ new_chain->parent = ldns_dnssec_build_data_chain(res, qflags, NULL, my_pkt, NULL); new_chain->parent->packet_qtype = LDNS_RR_TYPE_DS; } return new_chain; } ldns_dnssec_data_chain * ldns_dnssec_build_data_chain(ldns_resolver *res, uint16_t qflags, const ldns_rr_list *rrset, const ldns_pkt *pkt, ldns_rr *orig_rr) { ldns_rr_list *signatures = NULL; ldns_rr_list *dss = NULL; ldns_rr_list *my_rrset; ldns_pkt *my_pkt; ldns_rdf *name = NULL, *key_name = NULL; ldns_rr_type type = 0; ldns_rr_class c = 0; bool other_rrset = false; ldns_dnssec_data_chain *new_chain = ldns_dnssec_data_chain_new(); assert(pkt != NULL); if (!ldns_dnssec_pkt_has_rrsigs(pkt)) { /* hmm. no dnssec data in the packet. go up to try and deny * DS? */ return new_chain; } if (orig_rr) { new_chain->rrset = ldns_rr_list_new(); ldns_rr_list_push_rr(new_chain->rrset, orig_rr); new_chain->parent = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, NULL); new_chain->packet_rcode = ldns_pkt_get_rcode(pkt); new_chain->packet_qtype = ldns_rr_get_type(orig_rr); if (ldns_pkt_ancount(pkt) == 0) { new_chain->packet_nodata = true; } return new_chain; } if (!rrset || ldns_rr_list_rr_count(rrset) < 1) { /* hmm, no data, do we have denial? only works if pkt was given, otherwise caller has to do the check himself */ new_chain->packet_nodata = true; if (pkt) { my_rrset = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANY_NOQUESTION ); if (my_rrset) { if (ldns_rr_list_rr_count(my_rrset) > 0) { type = LDNS_RR_TYPE_NSEC; other_rrset = true; } else { ldns_rr_list_deep_free(my_rrset); my_rrset = NULL; } } else { /* nothing, try nsec3 */ my_rrset = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION); if (my_rrset) { if (ldns_rr_list_rr_count(my_rrset) > 0) { type = LDNS_RR_TYPE_NSEC3; other_rrset = true; } else { ldns_rr_list_deep_free(my_rrset); my_rrset = NULL; } } else { /* nothing, stop */ /* try parent zone? for denied insecure? */ return new_chain; } } } else { return new_chain; } } else { my_rrset = (ldns_rr_list *) rrset; } if (my_rrset && ldns_rr_list_rr_count(my_rrset) > 0) { new_chain->rrset = ldns_rr_list_clone(my_rrset); name = ldns_rr_owner(ldns_rr_list_rr(my_rrset, 0)); type = ldns_rr_get_type(ldns_rr_list_rr(my_rrset, 0)); c = ldns_rr_get_class(ldns_rr_list_rr(my_rrset, 0)); } if (other_rrset) { ldns_rr_list_deep_free(my_rrset); } /* normally there will only be 1 signature 'set' but there can be more than 1 denial (wildcards) so check for NSEC */ if (type == LDNS_RR_TYPE_NSEC || type == LDNS_RR_TYPE_NSEC3) { /* just throw in all signatures, the tree builder must sort this out */ if (pkt) { signatures = ldns_dnssec_pkt_get_rrsigs_for_type(pkt, type); } else { my_pkt = ldns_resolver_query(res, name, type, c, qflags); if (my_pkt) { signatures = ldns_dnssec_pkt_get_rrsigs_for_type(pkt, type); ldns_pkt_free(my_pkt); } } } else { if (pkt) { signatures = ldns_dnssec_pkt_get_rrsigs_for_name_and_type(pkt, name, type); } if (!signatures) { my_pkt = ldns_resolver_query(res, name, type, c, qflags); if (my_pkt) { signatures = ldns_dnssec_pkt_get_rrsigs_for_name_and_type(my_pkt, name, type); ldns_pkt_free(my_pkt); } } } if (signatures && ldns_rr_list_rr_count(signatures) > 0) { key_name = ldns_rr_rdf(ldns_rr_list_rr(signatures, 0), 7); } if (!key_name) { if (signatures) { ldns_rr_list_deep_free(signatures); } return ldns_dnssec_build_data_chain_nokeyname(res, qflags, orig_rr, rrset, new_chain); } if (type != LDNS_RR_TYPE_DNSKEY) { ldns_dnssec_build_data_chain_dnskey(res, qflags, pkt, signatures, new_chain, key_name, c ); } else { ldns_dnssec_build_data_chain_other(res, qflags, new_chain, key_name, c, dss ); } if (signatures) { ldns_rr_list_deep_free(signatures); } return new_chain; } ldns_dnssec_trust_tree * ldns_dnssec_trust_tree_new(void) { ldns_dnssec_trust_tree *new_tree = LDNS_XMALLOC(ldns_dnssec_trust_tree, 1); if(!new_tree) return NULL; new_tree->rr = NULL; new_tree->rrset = NULL; new_tree->parent_count = 0; return new_tree; } void ldns_dnssec_trust_tree_free(ldns_dnssec_trust_tree *tree) { size_t i; if (tree) { for (i = 0; i < tree->parent_count; i++) { ldns_dnssec_trust_tree_free(tree->parents[i]); } } LDNS_FREE(tree); } size_t ldns_dnssec_trust_tree_depth(ldns_dnssec_trust_tree *tree) { size_t result = 0; size_t parent = 0; size_t i; for (i = 0; i < tree->parent_count; i++) { parent = ldns_dnssec_trust_tree_depth(tree->parents[i]); if (parent > result) { result = parent; } } return 1 + result; } /* TODO ldns_ */ static void print_tabs(FILE *out, size_t nr, uint8_t *map, size_t treedepth) { size_t i; for (i = 0; i < nr; i++) { if (i == nr - 1) { fprintf(out, "|---"); } else if (map && i < treedepth && map[i] == 1) { fprintf(out, "| "); } else { fprintf(out, " "); } } } static void ldns_dnssec_trust_tree_print_sm_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_trust_tree *tree, size_t tabs, bool extended, uint8_t *sibmap, size_t treedepth) { size_t i; const ldns_rr_descriptor *descriptor; bool mapset = false; if (!sibmap) { treedepth = ldns_dnssec_trust_tree_depth(tree); sibmap = LDNS_XMALLOC(uint8_t, treedepth); if(!sibmap) return; /* mem err */ memset(sibmap, 0, treedepth); mapset = true; } if (tree) { if (tree->rr) { print_tabs(out, tabs, sibmap, treedepth); ldns_rdf_print(out, ldns_rr_owner(tree->rr)); descriptor = ldns_rr_descript(ldns_rr_get_type(tree->rr)); if (descriptor->_name) { fprintf(out, " (%s", descriptor->_name); } else { fprintf(out, " (TYPE%d", ldns_rr_get_type(tree->rr)); } if (tabs > 0) { if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_DNSKEY) { fprintf(out, " keytag: %u", (unsigned int) ldns_calc_keytag(tree->rr)); fprintf(out, " alg: "); ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 2)); fprintf(out, " flags: "); ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 0)); } else if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_DS) { fprintf(out, " keytag: "); ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 0)); fprintf(out, " digest type: "); ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 2)); } if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_NSEC) { fprintf(out, " "); ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 0)); fprintf(out, " "); ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 1)); } } fprintf(out, ")\n"); for (i = 0; i < tree->parent_count; i++) { if (tree->parent_count > 1 && i < tree->parent_count - 1) { sibmap[tabs] = 1; } else { sibmap[tabs] = 0; } /* only print errors */ if (ldns_rr_get_type(tree->parents[i]->rr) == LDNS_RR_TYPE_NSEC || ldns_rr_get_type(tree->parents[i]->rr) == LDNS_RR_TYPE_NSEC3) { if (tree->parent_status[i] == LDNS_STATUS_OK) { print_tabs(out, tabs + 1, sibmap, treedepth); if (tabs == 0 && ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_NS && ldns_rr_rd_count(tree->rr) > 0) { fprintf(out, "Existence of DS is denied by:\n"); } else { fprintf(out, "Existence is denied by:\n"); } } else { /* NS records aren't signed */ if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_NS) { fprintf(out, "Existence of DS is denied by:\n"); } else { print_tabs(out, tabs + 1, sibmap, treedepth); fprintf(out, "Error in denial of existence: %s\n", ldns_get_errorstr_by_id( tree->parent_status[i])); } } } else if (tree->parent_status[i] != LDNS_STATUS_OK) { print_tabs(out, tabs + 1, sibmap, treedepth); fprintf(out, "%s:\n", ldns_get_errorstr_by_id( tree->parent_status[i])); if (tree->parent_status[i] == LDNS_STATUS_SSL_ERR) { printf("; SSL Error: "); ERR_load_crypto_strings(); ERR_print_errors_fp(stdout); printf("\n"); } ldns_rr_print_fmt(out, fmt, tree-> parent_signature[i]); printf("For RRset:\n"); ldns_rr_list_print_fmt(out, fmt, tree->rrset); printf("With key:\n"); ldns_rr_print_fmt(out, fmt, tree->parents[i]->rr); } ldns_dnssec_trust_tree_print_sm_fmt(out, fmt, tree->parents[i], tabs+1, extended, sibmap, treedepth); } } else { print_tabs(out, tabs, sibmap, treedepth); fprintf(out, "\n"); } } else { fprintf(out, "\n"); } if (mapset) { LDNS_FREE(sibmap); } } void ldns_dnssec_trust_tree_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_trust_tree *tree, size_t tabs, bool extended) { ldns_dnssec_trust_tree_print_sm_fmt(out, fmt, tree, tabs, extended, NULL, 0); } void ldns_dnssec_trust_tree_print(FILE *out, ldns_dnssec_trust_tree *tree, size_t tabs, bool extended) { ldns_dnssec_trust_tree_print_fmt(out, ldns_output_format_default, tree, tabs, extended); } ldns_status ldns_dnssec_trust_tree_add_parent(ldns_dnssec_trust_tree *tree, const ldns_dnssec_trust_tree *parent, const ldns_rr *signature, const ldns_status parent_status) { if (tree && parent && tree->parent_count < LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS) { /* printf("Add parent for: "); ldns_rr_print(stdout, tree->rr); printf("parent: "); ldns_rr_print(stdout, parent->rr); */ tree->parents[tree->parent_count] = (ldns_dnssec_trust_tree *) parent; tree->parent_status[tree->parent_count] = parent_status; tree->parent_signature[tree->parent_count] = (ldns_rr *) signature; tree->parent_count++; return LDNS_STATUS_OK; } else { return LDNS_STATUS_ERR; } } /* if rr is null, take the first from the rrset */ ldns_dnssec_trust_tree * ldns_dnssec_derive_trust_tree_time( ldns_dnssec_data_chain *data_chain, ldns_rr *rr, time_t check_time ) { ldns_rr_list *cur_rrset; ldns_rr_list *cur_sigs; ldns_rr *cur_rr = NULL; ldns_rr *cur_sig_rr; size_t i, j; ldns_dnssec_trust_tree *new_tree = ldns_dnssec_trust_tree_new(); if(!new_tree) return NULL; if (data_chain && data_chain->rrset) { cur_rrset = data_chain->rrset; cur_sigs = data_chain->signatures; if (rr) { cur_rr = rr; } if (!cur_rr && ldns_rr_list_rr_count(cur_rrset) > 0) { cur_rr = ldns_rr_list_rr(cur_rrset, 0); } if (cur_rr) { new_tree->rr = cur_rr; new_tree->rrset = cur_rrset; /* there are three possibilities: 1 - 'normal' rrset, signed by a key 2 - dnskey signed by other dnskey 3 - dnskey proven by higher level DS (data denied by nsec is a special case that can occur in multiple places) */ if (cur_sigs) { for (i = 0; i < ldns_rr_list_rr_count(cur_sigs); i++) { /* find the appropriate key in the parent list */ cur_sig_rr = ldns_rr_list_rr(cur_sigs, i); if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_NSEC) { if (ldns_dname_compare(ldns_rr_owner(cur_sig_rr), ldns_rr_owner(cur_rr))) { /* find first that does match */ for (j = 0; j < ldns_rr_list_rr_count(cur_rrset) && ldns_dname_compare(ldns_rr_owner(cur_sig_rr),ldns_rr_owner(cur_rr)) != 0; j++) { cur_rr = ldns_rr_list_rr(cur_rrset, j); } if (ldns_dname_compare(ldns_rr_owner(cur_sig_rr), ldns_rr_owner(cur_rr))) { break; } } } /* option 1 */ if (data_chain->parent) { ldns_dnssec_derive_trust_tree_normal_rrset_time( new_tree, data_chain, cur_sig_rr, check_time); } /* option 2 */ ldns_dnssec_derive_trust_tree_dnskey_rrset_time( new_tree, data_chain, cur_rr, cur_sig_rr, check_time); } ldns_dnssec_derive_trust_tree_ds_rrset_time( new_tree, data_chain, cur_rr, check_time); } else { /* no signatures? maybe it's nsec data */ /* just add every rr from parent as new parent */ ldns_dnssec_derive_trust_tree_no_sig_time( new_tree, data_chain, check_time); } } } return new_tree; } ldns_dnssec_trust_tree * ldns_dnssec_derive_trust_tree(ldns_dnssec_data_chain *data_chain, ldns_rr *rr) { return ldns_dnssec_derive_trust_tree_time(data_chain, rr, ldns_time(NULL)); } void ldns_dnssec_derive_trust_tree_normal_rrset_time( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_sig_rr, time_t check_time) { size_t i, j; ldns_rr_list *cur_rrset = ldns_rr_list_clone(data_chain->rrset); ldns_dnssec_trust_tree *cur_parent_tree; ldns_rr *cur_parent_rr; uint16_t cur_keytag; ldns_rr_list *tmp_rrset = NULL; ldns_status cur_status; cur_keytag = ldns_rdf2native_int16(ldns_rr_rrsig_keytag(cur_sig_rr)); for (j = 0; j < ldns_rr_list_rr_count(data_chain->parent->rrset); j++) { cur_parent_rr = ldns_rr_list_rr(data_chain->parent->rrset, j); if (ldns_rr_get_type(cur_parent_rr) == LDNS_RR_TYPE_DNSKEY) { if (ldns_calc_keytag(cur_parent_rr) == cur_keytag) { /* TODO: check wildcard nsec too */ if (cur_rrset && ldns_rr_list_rr_count(cur_rrset) > 0) { tmp_rrset = cur_rrset; if (ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0)) == LDNS_RR_TYPE_NSEC || ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0)) == LDNS_RR_TYPE_NSEC3) { /* might contain different names! sort and split */ ldns_rr_list_sort(cur_rrset); assert(tmp_rrset == cur_rrset); tmp_rrset = ldns_rr_list_pop_rrset(cur_rrset); /* with nsecs, this might be the wrong one */ while (tmp_rrset && ldns_rr_list_rr_count(cur_rrset) > 0 && ldns_dname_compare( ldns_rr_owner(ldns_rr_list_rr( tmp_rrset, 0)), ldns_rr_owner(cur_sig_rr)) != 0) { ldns_rr_list_deep_free(tmp_rrset); tmp_rrset = ldns_rr_list_pop_rrset(cur_rrset); } } cur_status = ldns_verify_rrsig_time( tmp_rrset, cur_sig_rr, cur_parent_rr, check_time); if (tmp_rrset && tmp_rrset != cur_rrset ) { ldns_rr_list_deep_free( tmp_rrset); tmp_rrset = NULL; } /* avoid dupes */ for (i = 0; i < new_tree->parent_count; i++) { if (cur_parent_rr == new_tree->parents[i]->rr) { goto done; } } cur_parent_tree = ldns_dnssec_derive_trust_tree_time( data_chain->parent, cur_parent_rr, check_time); (void)ldns_dnssec_trust_tree_add_parent(new_tree, cur_parent_tree, cur_sig_rr, cur_status); } } } } done: ldns_rr_list_deep_free(cur_rrset); } void ldns_dnssec_derive_trust_tree_normal_rrset(ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_sig_rr) { ldns_dnssec_derive_trust_tree_normal_rrset_time( new_tree, data_chain, cur_sig_rr, ldns_time(NULL)); } void ldns_dnssec_derive_trust_tree_dnskey_rrset_time( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_rr, ldns_rr *cur_sig_rr, time_t check_time) { size_t j; ldns_rr_list *cur_rrset = data_chain->rrset; ldns_dnssec_trust_tree *cur_parent_tree; ldns_rr *cur_parent_rr; uint16_t cur_keytag; ldns_status cur_status; cur_keytag = ldns_rdf2native_int16(ldns_rr_rrsig_keytag(cur_sig_rr)); for (j = 0; j < ldns_rr_list_rr_count(cur_rrset); j++) { cur_parent_rr = ldns_rr_list_rr(cur_rrset, j); if (cur_parent_rr != cur_rr && ldns_rr_get_type(cur_parent_rr) == LDNS_RR_TYPE_DNSKEY) { if (ldns_calc_keytag(cur_parent_rr) == cur_keytag ) { cur_parent_tree = ldns_dnssec_trust_tree_new(); cur_parent_tree->rr = cur_parent_rr; cur_parent_tree->rrset = cur_rrset; cur_status = ldns_verify_rrsig_time( cur_rrset, cur_sig_rr, cur_parent_rr, check_time); (void) ldns_dnssec_trust_tree_add_parent(new_tree, cur_parent_tree, cur_sig_rr, cur_status); } } } } void ldns_dnssec_derive_trust_tree_dnskey_rrset(ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_rr, ldns_rr *cur_sig_rr) { ldns_dnssec_derive_trust_tree_dnskey_rrset_time( new_tree, data_chain, cur_rr, cur_sig_rr, ldns_time(NULL)); } void ldns_dnssec_derive_trust_tree_ds_rrset_time( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_rr, time_t check_time) { size_t j, h; ldns_rr_list *cur_rrset = data_chain->rrset; ldns_dnssec_trust_tree *cur_parent_tree; ldns_rr *cur_parent_rr; /* try the parent to see whether there are DSs there */ if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_DNSKEY && data_chain->parent && data_chain->parent->rrset ) { for (j = 0; j < ldns_rr_list_rr_count(data_chain->parent->rrset); j++) { cur_parent_rr = ldns_rr_list_rr(data_chain->parent->rrset, j); if (ldns_rr_get_type(cur_parent_rr) == LDNS_RR_TYPE_DS) { for (h = 0; h < ldns_rr_list_rr_count(cur_rrset); h++) { cur_rr = ldns_rr_list_rr(cur_rrset, h); if (ldns_rr_compare_ds(cur_rr, cur_parent_rr)) { cur_parent_tree = ldns_dnssec_derive_trust_tree_time( data_chain->parent, cur_parent_rr, check_time); (void) ldns_dnssec_trust_tree_add_parent( new_tree, cur_parent_tree, NULL, LDNS_STATUS_OK); } else { /*ldns_rr_print(stdout, cur_parent_rr);*/ } } } } } } void ldns_dnssec_derive_trust_tree_ds_rrset(ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_rr) { ldns_dnssec_derive_trust_tree_ds_rrset_time( new_tree, data_chain, cur_rr, ldns_time(NULL)); } void ldns_dnssec_derive_trust_tree_no_sig_time( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, time_t check_time) { size_t i; ldns_rr_list *cur_rrset; ldns_rr *cur_parent_rr; ldns_dnssec_trust_tree *cur_parent_tree; ldns_status result; if (data_chain->parent && data_chain->parent->rrset) { cur_rrset = data_chain->parent->rrset; /* nsec? */ if (cur_rrset && ldns_rr_list_rr_count(cur_rrset) > 0) { if (ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0)) == LDNS_RR_TYPE_NSEC3) { result = ldns_dnssec_verify_denial_nsec3( new_tree->rr, cur_rrset, data_chain->parent->signatures, data_chain->packet_rcode, data_chain->packet_qtype, data_chain->packet_nodata); } else if (ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0)) == LDNS_RR_TYPE_NSEC) { result = ldns_dnssec_verify_denial( new_tree->rr, cur_rrset, data_chain->parent->signatures); } else { /* unsigned zone, unsigned parent */ result = LDNS_STATUS_OK; } } else { result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED; } for (i = 0; i < ldns_rr_list_rr_count(cur_rrset); i++) { cur_parent_rr = ldns_rr_list_rr(cur_rrset, i); cur_parent_tree = ldns_dnssec_derive_trust_tree_time( data_chain->parent, cur_parent_rr, check_time); (void) ldns_dnssec_trust_tree_add_parent(new_tree, cur_parent_tree, NULL, result); } } } void ldns_dnssec_derive_trust_tree_no_sig(ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain) { ldns_dnssec_derive_trust_tree_no_sig_time( new_tree, data_chain, ldns_time(NULL)); } /* * returns OK if there is a path from tree to key with only OK * the (first) error in between otherwise * or NOT_FOUND if the key wasn't present at all */ ldns_status ldns_dnssec_trust_tree_contains_keys(ldns_dnssec_trust_tree *tree, ldns_rr_list *trusted_keys) { size_t i; ldns_status result = LDNS_STATUS_CRYPTO_NO_DNSKEY; bool equal; ldns_status parent_result; if (tree && trusted_keys && ldns_rr_list_rr_count(trusted_keys) > 0) { if (tree->rr) { for (i = 0; i < ldns_rr_list_rr_count(trusted_keys); i++) { equal = ldns_rr_compare_ds( tree->rr, ldns_rr_list_rr(trusted_keys, i)); if (equal) { result = LDNS_STATUS_OK; return result; } } } for (i = 0; i < tree->parent_count; i++) { parent_result = ldns_dnssec_trust_tree_contains_keys(tree->parents[i], trusted_keys); if (parent_result != LDNS_STATUS_CRYPTO_NO_DNSKEY) { if (tree->parent_status[i] != LDNS_STATUS_OK) { result = tree->parent_status[i]; } else { if (tree->rr && ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_NSEC && parent_result == LDNS_STATUS_OK ) { result = LDNS_STATUS_DNSSEC_EXISTENCE_DENIED; } else { result = parent_result; } } } } } else { result = LDNS_STATUS_ERR; } return result; } ldns_status ldns_verify_time( ldns_rr_list *rrset, ldns_rr_list *rrsig, const ldns_rr_list *keys, time_t check_time, ldns_rr_list *good_keys ) { uint16_t i; ldns_status verify_result = LDNS_STATUS_ERR; if (!rrset || !rrsig || !keys) { return LDNS_STATUS_ERR; } if (ldns_rr_list_rr_count(rrset) < 1) { return LDNS_STATUS_ERR; } if (ldns_rr_list_rr_count(rrsig) < 1) { return LDNS_STATUS_CRYPTO_NO_RRSIG; } if (ldns_rr_list_rr_count(keys) < 1) { verify_result = LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY; } else { for (i = 0; i < ldns_rr_list_rr_count(rrsig); i++) { ldns_status s = ldns_verify_rrsig_keylist_time( rrset, ldns_rr_list_rr(rrsig, i), keys, check_time, good_keys); /* try a little to get more descriptive error */ if(s == LDNS_STATUS_OK) { verify_result = LDNS_STATUS_OK; } else if(verify_result == LDNS_STATUS_ERR) verify_result = s; else if(s != LDNS_STATUS_ERR && verify_result == LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY) verify_result = s; } } return verify_result; } ldns_status ldns_verify(ldns_rr_list *rrset, ldns_rr_list *rrsig, const ldns_rr_list *keys, ldns_rr_list *good_keys) { return ldns_verify_time(rrset, rrsig, keys, ldns_time(NULL), good_keys); } ldns_status ldns_verify_notime(ldns_rr_list *rrset, ldns_rr_list *rrsig, const ldns_rr_list *keys, ldns_rr_list *good_keys) { uint16_t i; ldns_status verify_result = LDNS_STATUS_ERR; if (!rrset || !rrsig || !keys) { return LDNS_STATUS_ERR; } if (ldns_rr_list_rr_count(rrset) < 1) { return LDNS_STATUS_ERR; } if (ldns_rr_list_rr_count(rrsig) < 1) { return LDNS_STATUS_CRYPTO_NO_RRSIG; } if (ldns_rr_list_rr_count(keys) < 1) { verify_result = LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY; } else { for (i = 0; i < ldns_rr_list_rr_count(rrsig); i++) { ldns_status s = ldns_verify_rrsig_keylist_notime(rrset, ldns_rr_list_rr(rrsig, i), keys, good_keys); /* try a little to get more descriptive error */ if (s == LDNS_STATUS_OK) { verify_result = LDNS_STATUS_OK; } else if (verify_result == LDNS_STATUS_ERR) { verify_result = s; } else if (s != LDNS_STATUS_ERR && verify_result == LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY) { verify_result = s; } } } return verify_result; } ldns_rr_list * ldns_fetch_valid_domain_keys_time(const ldns_resolver *res, const ldns_rdf *domain, const ldns_rr_list *keys, time_t check_time, ldns_status *status) { ldns_rr_list * trusted_keys = NULL; ldns_rr_list * ds_keys = NULL; ldns_rdf * prev_parent_domain; ldns_rdf * parent_domain; ldns_rr_list * parent_keys = NULL; if (res && domain && keys) { if ((trusted_keys = ldns_validate_domain_dnskey_time(res, domain, keys, check_time))) { *status = LDNS_STATUS_OK; } else { /* No trusted keys in this domain, we'll have to find some in the parent domain */ *status = LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY; parent_domain = ldns_dname_left_chop(domain); while (parent_domain && /* Fail if we are at the root*/ ldns_rdf_size(parent_domain) > 0) { if ((parent_keys = ldns_fetch_valid_domain_keys_time(res, parent_domain, keys, check_time, status))) { /* Check DS records */ if ((ds_keys = ldns_validate_domain_ds_time(res, domain, parent_keys, check_time))) { trusted_keys = ldns_fetch_valid_domain_keys_time( res, domain, ds_keys, check_time, status); ldns_rr_list_deep_free(ds_keys); } else { /* No valid DS at the parent -- fail */ *status = LDNS_STATUS_CRYPTO_NO_TRUSTED_DS ; } ldns_rr_list_deep_free(parent_keys); break; } else { parent_domain = ldns_dname_left_chop(( prev_parent_domain = parent_domain )); ldns_rdf_deep_free(prev_parent_domain); } } if (parent_domain) { ldns_rdf_deep_free(parent_domain); } } } return trusted_keys; } ldns_rr_list * ldns_fetch_valid_domain_keys(const ldns_resolver *res, const ldns_rdf *domain, const ldns_rr_list *keys, ldns_status *status) { return ldns_fetch_valid_domain_keys_time( res, domain, keys, ldns_time(NULL), status); } ldns_rr_list * ldns_validate_domain_dnskey_time( const ldns_resolver * res, const ldns_rdf * domain, const ldns_rr_list * keys, time_t check_time ) { ldns_pkt * keypkt; ldns_rr * cur_key; uint16_t key_i; uint16_t key_j; uint16_t key_k; uint16_t sig_i; ldns_rr * cur_sig; ldns_rr_list * domain_keys = NULL; ldns_rr_list * domain_sigs = NULL; ldns_rr_list * trusted_keys = NULL; /* Fetch keys for the domain */ keypkt = ldns_resolver_query(res, domain, LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, LDNS_RD); if (keypkt) { domain_keys = ldns_pkt_rr_list_by_type(keypkt, LDNS_RR_TYPE_DNSKEY, LDNS_SECTION_ANSWER); domain_sigs = ldns_pkt_rr_list_by_type(keypkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANSWER); /* Try to validate the record using our keys */ for (key_i=0; key_i< ldns_rr_list_rr_count(domain_keys); key_i++) { cur_key = ldns_rr_list_rr(domain_keys, key_i); for (key_j=0; key_j= ldns_dname_label_count(ldns_rr_owner(rr))) { /* Query name *is* the "next closer". */ hashed_next_closer = hashed_name; } else { /* "next closer" has less labels than the query name. * Create the name and hash it. */ next_closer = ldns_dname_clone_from( ldns_rr_owner(rr), ldns_dname_label_count(ldns_rr_owner(rr)) - (ldns_dname_label_count(closest_encloser) + 1) ); hashed_next_closer = ldns_nsec3_hash_name_frm_nsec3( ldns_rr_list_rr(nsecs, 0), next_closer ); (void) ldns_dname_cat(hashed_next_closer, zone_name); } /* Find the NSEC3 that covers the "next closer" */ for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) { if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, i), hashed_next_closer) && ldns_nsec3_optout(ldns_rr_list_rr(nsecs, i))) { result = LDNS_STATUS_OK; if (match) { *match = ldns_rr_list_rr(nsecs, i); } break; } } if (ldns_dname_label_count(closest_encloser) + 1 < ldns_dname_label_count(ldns_rr_owner(rr))) { /* "next closer" has less labels than the query name. * Dispose of the temporary variables that held that name. */ ldns_rdf_deep_free(hashed_next_closer); ldns_rdf_deep_free(next_closer); } ldns_rdf_deep_free(closest_encloser); } done: ldns_rdf_deep_free(zone_name); return result; } ldns_status ldns_dnssec_verify_denial_nsec3(ldns_rr *rr, ldns_rr_list *nsecs, ldns_rr_list *rrsigs, ldns_pkt_rcode packet_rcode, ldns_rr_type packet_qtype, bool packet_nodata) { return ldns_dnssec_verify_denial_nsec3_match( rr, nsecs, rrsigs, packet_rcode, packet_qtype, packet_nodata, NULL ); } #ifdef USE_GOST EVP_PKEY* ldns_gost2pkey_raw(unsigned char* key, size_t keylen) { /* prefix header for X509 encoding */ uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40}; unsigned char encoded[37+64]; const unsigned char* pp; if(keylen != 64) { /* key wrong size */ return NULL; } /* create evp_key */ memmove(encoded, asn, 37); memmove(encoded+37, key, 64); pp = (unsigned char*)&encoded[0]; return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded)); } static ldns_status ldns_verify_rrsig_gost_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen) { EVP_PKEY *evp_key; ldns_status result; (void) ldns_key_EVP_load_gost_id(); evp_key = ldns_gost2pkey_raw(key, keylen); if(!evp_key) { /* could not convert key */ return LDNS_STATUS_CRYPTO_BOGUS; } /* verify signature */ result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key, EVP_get_digestbyname("md_gost94")); EVP_PKEY_free(evp_key); return result; } #endif #ifdef USE_ECDSA EVP_PKEY* ldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo) { unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */ const unsigned char* pp = buf; EVP_PKEY *evp_key; EC_KEY *ec; /* check length, which uncompressed must be 2 bignums */ if(algo == LDNS_ECDSAP256SHA256) { if(keylen != 2*256/8) return NULL; ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); } else if(algo == LDNS_ECDSAP384SHA384) { if(keylen != 2*384/8) return NULL; ec = EC_KEY_new_by_curve_name(NID_secp384r1); } else ec = NULL; if(!ec) return NULL; if(keylen+1 > sizeof(buf)) return NULL; /* sanity check */ /* prepend the 0x02 (from docs) (or actually 0x04 from implementation * of openssl) for uncompressed data */ buf[0] = POINT_CONVERSION_UNCOMPRESSED; memmove(buf+1, key, keylen); if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) { EC_KEY_free(ec); return NULL; } evp_key = EVP_PKEY_new(); if(!evp_key) { EC_KEY_free(ec); return NULL; } if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) { EVP_PKEY_free(evp_key); EC_KEY_free(ec); return NULL; } return evp_key; } static ldns_status ldns_verify_rrsig_ecdsa_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen, uint8_t algo) { EVP_PKEY *evp_key; ldns_status result; const EVP_MD *d; evp_key = ldns_ecdsa2pkey_raw(key, keylen, algo); if(!evp_key) { /* could not convert key */ return LDNS_STATUS_CRYPTO_BOGUS; } if(algo == LDNS_ECDSAP256SHA256) d = EVP_sha256(); else d = EVP_sha384(); /* LDNS_ECDSAP384SHA384 */ result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key, d); EVP_PKEY_free(evp_key); return result; } #endif ldns_status ldns_verify_rrsig_buffers(ldns_buffer *rawsig_buf, ldns_buffer *verify_buf, ldns_buffer *key_buf, uint8_t algo) { return ldns_verify_rrsig_buffers_raw( (unsigned char*)ldns_buffer_begin(rawsig_buf), ldns_buffer_position(rawsig_buf), verify_buf, (unsigned char*)ldns_buffer_begin(key_buf), ldns_buffer_position(key_buf), algo); } ldns_status ldns_verify_rrsig_buffers_raw(unsigned char* sig, size_t siglen, ldns_buffer *verify_buf, unsigned char* key, size_t keylen, uint8_t algo) { /* check for right key */ switch(algo) { case LDNS_DSA: case LDNS_DSA_NSEC3: return ldns_verify_rrsig_dsa_raw(sig, siglen, verify_buf, key, keylen); break; case LDNS_RSASHA1: case LDNS_RSASHA1_NSEC3: return ldns_verify_rrsig_rsasha1_raw(sig, siglen, verify_buf, key, keylen); break; #ifdef USE_SHA2 case LDNS_RSASHA256: return ldns_verify_rrsig_rsasha256_raw(sig, siglen, verify_buf, key, keylen); break; case LDNS_RSASHA512: return ldns_verify_rrsig_rsasha512_raw(sig, siglen, verify_buf, key, keylen); break; #endif #ifdef USE_GOST case LDNS_ECC_GOST: return ldns_verify_rrsig_gost_raw(sig, siglen, verify_buf, key, keylen); break; #endif #ifdef USE_ECDSA case LDNS_ECDSAP256SHA256: case LDNS_ECDSAP384SHA384: return ldns_verify_rrsig_ecdsa_raw(sig, siglen, verify_buf, key, keylen, algo); break; #endif case LDNS_RSAMD5: return ldns_verify_rrsig_rsamd5_raw(sig, siglen, verify_buf, key, keylen); break; default: /* do you know this alg?! */ return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO; } } /** * Reset the ttl in the rrset with the orig_ttl from the sig * and update owner name if it was wildcard * Also canonicalizes the rrset. * @param rrset: rrset to modify * @param sig: signature to take TTL and wildcard values from */ static void ldns_rrset_use_signature_ttl(ldns_rr_list* rrset_clone, ldns_rr* rrsig) { uint32_t orig_ttl; uint16_t i; uint8_t label_count; ldns_rdf *wildcard_name; ldns_rdf *wildcard_chopped; ldns_rdf *wildcard_chopped_tmp; if ((rrsig == NULL) || ldns_rr_rd_count(rrsig) < 4) { return; } orig_ttl = ldns_rdf2native_int32( ldns_rr_rdf(rrsig, 3)); label_count = ldns_rdf2native_int8(ldns_rr_rdf(rrsig, 2)); for(i = 0; i < ldns_rr_list_rr_count(rrset_clone); i++) { if (label_count < ldns_dname_label_count( ldns_rr_owner(ldns_rr_list_rr(rrset_clone, i)))) { (void) ldns_str2rdf_dname(&wildcard_name, "*"); wildcard_chopped = ldns_rdf_clone(ldns_rr_owner( ldns_rr_list_rr(rrset_clone, i))); while (label_count < ldns_dname_label_count(wildcard_chopped)) { wildcard_chopped_tmp = ldns_dname_left_chop( wildcard_chopped); ldns_rdf_deep_free(wildcard_chopped); wildcard_chopped = wildcard_chopped_tmp; } (void) ldns_dname_cat(wildcard_name, wildcard_chopped); ldns_rdf_deep_free(wildcard_chopped); ldns_rdf_deep_free(ldns_rr_owner(ldns_rr_list_rr( rrset_clone, i))); ldns_rr_set_owner(ldns_rr_list_rr(rrset_clone, i), wildcard_name); } ldns_rr_set_ttl(ldns_rr_list_rr(rrset_clone, i), orig_ttl); /* convert to lowercase */ ldns_rr2canonical(ldns_rr_list_rr(rrset_clone, i)); } } /** * Make raw signature buffer out of rrsig * @param rawsig_buf: raw signature buffer for result * @param rrsig: signature to convert * @return OK or more specific error. */ static ldns_status ldns_rrsig2rawsig_buffer(ldns_buffer* rawsig_buf, ldns_rr* rrsig) { uint8_t sig_algo; if (rrsig == NULL) { return LDNS_STATUS_CRYPTO_NO_RRSIG; } if (ldns_rr_rdf(rrsig, 1) == NULL) { return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG; } sig_algo = ldns_rdf2native_int8(ldns_rr_rdf(rrsig, 1)); /* check for known and implemented algo's now (otherwise * the function could return a wrong error */ /* create a buffer with signature rdata */ /* for some algorithms we need other data than for others... */ /* (the DSA API wants DER encoding for instance) */ switch(sig_algo) { case LDNS_RSAMD5: case LDNS_RSASHA1: case LDNS_RSASHA1_NSEC3: #ifdef USE_SHA2 case LDNS_RSASHA256: case LDNS_RSASHA512: #endif #ifdef USE_GOST case LDNS_ECC_GOST: #endif if (ldns_rr_rdf(rrsig, 8) == NULL) { return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG; } if (ldns_rdf2buffer_wire(rawsig_buf, ldns_rr_rdf(rrsig, 8)) != LDNS_STATUS_OK) { return LDNS_STATUS_MEM_ERR; } break; case LDNS_DSA: case LDNS_DSA_NSEC3: /* EVP takes rfc2459 format, which is a tad longer than dns format */ if (ldns_rr_rdf(rrsig, 8) == NULL) { return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG; } if (ldns_convert_dsa_rrsig_rdf2asn1( rawsig_buf, ldns_rr_rdf(rrsig, 8)) != LDNS_STATUS_OK) { /* if (ldns_rdf2buffer_wire(rawsig_buf, ldns_rr_rdf(rrsig, 8)) != LDNS_STATUS_OK) { */ return LDNS_STATUS_MEM_ERR; } break; #ifdef USE_ECDSA case LDNS_ECDSAP256SHA256: case LDNS_ECDSAP384SHA384: /* EVP produces an ASN prefix on the signature, which is * not used in the DNS */ if (ldns_rr_rdf(rrsig, 8) == NULL) { return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG; } if (ldns_convert_ecdsa_rrsig_rdf2asn1( rawsig_buf, ldns_rr_rdf(rrsig, 8)) != LDNS_STATUS_OK) { return LDNS_STATUS_MEM_ERR; } break; #endif case LDNS_DH: case LDNS_ECC: case LDNS_INDIRECT: return LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL; default: return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO; } return LDNS_STATUS_OK; } /** * Check RRSIG timestamps against the given 'now' time. * @param rrsig: signature to check. * @param now: the current time in seconds epoch. * @return status code LDNS_STATUS_OK if all is fine. */ static ldns_status ldns_rrsig_check_timestamps(ldns_rr* rrsig, time_t now) { int32_t inception, expiration; /* check the signature time stamps */ inception = (int32_t)ldns_rdf2native_time_t( ldns_rr_rrsig_inception(rrsig)); expiration = (int32_t)ldns_rdf2native_time_t( ldns_rr_rrsig_expiration(rrsig)); if (expiration - inception < 0) { /* bad sig, expiration before inception?? Tsssg */ return LDNS_STATUS_CRYPTO_EXPIRATION_BEFORE_INCEPTION; } if (((int32_t) now) - inception < 0) { /* bad sig, inception date has not yet come to pass */ return LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED; } if (expiration - ((int32_t) now) < 0) { /* bad sig, expiration date has passed */ return LDNS_STATUS_CRYPTO_SIG_EXPIRED; } return LDNS_STATUS_OK; } /** * Prepare for verification. * @param rawsig_buf: raw signature buffer made ready. * @param verify_buf: data for verification buffer made ready. * @param rrset_clone: made ready. * @param rrsig: signature to prepare for. * @return LDNS_STATUS_OK is all went well. Otherwise specific error. */ static ldns_status ldns_prepare_for_verify(ldns_buffer* rawsig_buf, ldns_buffer* verify_buf, ldns_rr_list* rrset_clone, ldns_rr* rrsig) { ldns_status result; /* canonicalize the sig */ ldns_dname2canonical(ldns_rr_owner(rrsig)); /* check if the typecovered is equal to the type checked */ if (ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rrsig)) != ldns_rr_get_type(ldns_rr_list_rr(rrset_clone, 0))) return LDNS_STATUS_CRYPTO_TYPE_COVERED_ERR; /* create a buffer with b64 signature rdata */ result = ldns_rrsig2rawsig_buffer(rawsig_buf, rrsig); if(result != LDNS_STATUS_OK) return result; /* use TTL from signature. Use wildcard names for wildcards */ /* also canonicalizes rrset_clone */ ldns_rrset_use_signature_ttl(rrset_clone, rrsig); /* sort the rrset in canonical order */ ldns_rr_list_sort(rrset_clone); /* put the signature rr (without the b64) to the verify_buf */ if (ldns_rrsig2buffer_wire(verify_buf, rrsig) != LDNS_STATUS_OK) return LDNS_STATUS_MEM_ERR; /* add the rrset in verify_buf */ if(ldns_rr_list2buffer_wire(verify_buf, rrset_clone) != LDNS_STATUS_OK) return LDNS_STATUS_MEM_ERR; return LDNS_STATUS_OK; } /** * Check if a key matches a signature. * Checks keytag, sigalgo and signature. * @param rawsig_buf: raw signature buffer for verify * @param verify_buf: raw data buffer for verify * @param rrsig: the rrsig * @param key: key to attempt. * @return LDNS_STATUS_OK if OK, else some specific error. */ static ldns_status ldns_verify_test_sig_key(ldns_buffer* rawsig_buf, ldns_buffer* verify_buf, ldns_rr* rrsig, ldns_rr* key) { uint8_t sig_algo; if (rrsig == NULL) { return LDNS_STATUS_CRYPTO_NO_RRSIG; } if (ldns_rr_rdf(rrsig, 1) == NULL) { return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG; } sig_algo = ldns_rdf2native_int8(ldns_rr_rdf(rrsig, 1)); /* before anything, check if the keytags match */ if (ldns_calc_keytag(key) == ldns_rdf2native_int16(ldns_rr_rrsig_keytag(rrsig)) ) { ldns_buffer* key_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN); ldns_status result = LDNS_STATUS_ERR; /* put the key-data in a buffer, that's the third rdf, with * the base64 encoded key data */ if (ldns_rr_rdf(key, 3) == NULL) { ldns_buffer_free(key_buf); return LDNS_STATUS_MISSING_RDATA_FIELDS_KEY; } if (ldns_rdf2buffer_wire(key_buf, ldns_rr_rdf(key, 3)) != LDNS_STATUS_OK) { ldns_buffer_free(key_buf); /* returning is bad might screw up good keys later in the list what to do? */ return LDNS_STATUS_ERR; } if (ldns_rr_rdf(key, 2) == NULL) { result = LDNS_STATUS_MISSING_RDATA_FIELDS_KEY; } else if (sig_algo == ldns_rdf2native_int8( ldns_rr_rdf(key, 2))) { result = ldns_verify_rrsig_buffers(rawsig_buf, verify_buf, key_buf, sig_algo); } else { /* No keys with the corresponding algorithm are found */ result = LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY; } ldns_buffer_free(key_buf); return result; } else { /* No keys with the corresponding keytag are found */ return LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY; } } /* * to verify: * - create the wire fmt of the b64 key rdata * - create the wire fmt of the sorted rrset * - create the wire fmt of the b64 sig rdata * - create the wire fmt of the sig without the b64 rdata * - cat the sig data (without b64 rdata) to the rrset * - verify the rrset+sig, with the b64 data and the b64 key data */ ldns_status ldns_verify_rrsig_keylist_time( ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_list *keys, time_t check_time, ldns_rr_list *good_keys) { ldns_status result; ldns_rr_list *valid = ldns_rr_list_new(); if (!valid) return LDNS_STATUS_MEM_ERR; result = ldns_verify_rrsig_keylist_notime(rrset, rrsig, keys, valid); if(result != LDNS_STATUS_OK) { ldns_rr_list_free(valid); return result; } /* check timestamps last; its OK except time */ result = ldns_rrsig_check_timestamps(rrsig, check_time); if(result != LDNS_STATUS_OK) { ldns_rr_list_free(valid); return result; } ldns_rr_list_cat(good_keys, valid); ldns_rr_list_free(valid); return LDNS_STATUS_OK; } /* * to verify: * - create the wire fmt of the b64 key rdata * - create the wire fmt of the sorted rrset * - create the wire fmt of the b64 sig rdata * - create the wire fmt of the sig without the b64 rdata * - cat the sig data (without b64 rdata) to the rrset * - verify the rrset+sig, with the b64 data and the b64 key data */ ldns_status ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_list *keys, ldns_rr_list *good_keys) { return ldns_verify_rrsig_keylist_time( rrset, rrsig, keys, ldns_time(NULL), good_keys); } ldns_status ldns_verify_rrsig_keylist_notime(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_list *keys, ldns_rr_list *good_keys) { ldns_buffer *rawsig_buf; ldns_buffer *verify_buf; uint16_t i; ldns_status result, status; ldns_rr_list *rrset_clone; ldns_rr_list *validkeys; if (!rrset) { return LDNS_STATUS_ERR; } validkeys = ldns_rr_list_new(); if (!validkeys) { return LDNS_STATUS_MEM_ERR; } /* clone the rrset so that we can fiddle with it */ rrset_clone = ldns_rr_list_clone(rrset); /* create the buffers which will certainly hold the raw data */ rawsig_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN); verify_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN); result = ldns_prepare_for_verify(rawsig_buf, verify_buf, rrset_clone, rrsig); if(result != LDNS_STATUS_OK) { ldns_buffer_free(verify_buf); ldns_buffer_free(rawsig_buf); ldns_rr_list_deep_free(rrset_clone); ldns_rr_list_free(validkeys); return result; } result = LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY; for(i = 0; i < ldns_rr_list_rr_count(keys); i++) { status = ldns_verify_test_sig_key(rawsig_buf, verify_buf, rrsig, ldns_rr_list_rr(keys, i)); if (status == LDNS_STATUS_OK) { /* one of the keys has matched, don't break * here, instead put the 'winning' key in * the validkey list and return the list * later */ if (!ldns_rr_list_push_rr(validkeys, ldns_rr_list_rr(keys,i))) { /* couldn't push the key?? */ ldns_buffer_free(rawsig_buf); ldns_buffer_free(verify_buf); ldns_rr_list_deep_free(rrset_clone); ldns_rr_list_free(validkeys); return LDNS_STATUS_MEM_ERR; } result = status; } if (result == LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY) { result = status; } } /* no longer needed */ ldns_rr_list_deep_free(rrset_clone); ldns_buffer_free(rawsig_buf); ldns_buffer_free(verify_buf); if (ldns_rr_list_rr_count(validkeys) == 0) { /* no keys were added, return last error */ ldns_rr_list_free(validkeys); return result; } /* do not check timestamps */ ldns_rr_list_cat(good_keys, validkeys); ldns_rr_list_free(validkeys); return LDNS_STATUS_OK; } ldns_status ldns_verify_rrsig_time( ldns_rr_list *rrset, ldns_rr *rrsig, ldns_rr *key, time_t check_time) { ldns_buffer *rawsig_buf; ldns_buffer *verify_buf; ldns_status result; ldns_rr_list *rrset_clone; if (!rrset) { return LDNS_STATUS_NO_DATA; } /* clone the rrset so that we can fiddle with it */ rrset_clone = ldns_rr_list_clone(rrset); /* create the buffers which will certainly hold the raw data */ rawsig_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN); verify_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN); result = ldns_prepare_for_verify(rawsig_buf, verify_buf, rrset_clone, rrsig); if(result != LDNS_STATUS_OK) { ldns_rr_list_deep_free(rrset_clone); ldns_buffer_free(rawsig_buf); ldns_buffer_free(verify_buf); return result; } result = ldns_verify_test_sig_key(rawsig_buf, verify_buf, rrsig, key); /* no longer needed */ ldns_rr_list_deep_free(rrset_clone); ldns_buffer_free(rawsig_buf); ldns_buffer_free(verify_buf); /* check timestamp last, apart from time its OK */ if(result == LDNS_STATUS_OK) result = ldns_rrsig_check_timestamps(rrsig, check_time); return result; } ldns_status ldns_verify_rrsig(ldns_rr_list *rrset, ldns_rr *rrsig, ldns_rr *key) { return ldns_verify_rrsig_time(rrset, rrsig, key, ldns_time(NULL)); } ldns_status ldns_verify_rrsig_evp(ldns_buffer *sig, ldns_buffer *rrset, EVP_PKEY *key, const EVP_MD *digest_type) { return ldns_verify_rrsig_evp_raw( (unsigned char*)ldns_buffer_begin(sig), ldns_buffer_position(sig), rrset, key, digest_type); } ldns_status ldns_verify_rrsig_evp_raw(unsigned char *sig, size_t siglen, ldns_buffer *rrset, EVP_PKEY *key, const EVP_MD *digest_type) { EVP_MD_CTX ctx; int res; EVP_MD_CTX_init(&ctx); EVP_VerifyInit(&ctx, digest_type); EVP_VerifyUpdate(&ctx, ldns_buffer_begin(rrset), ldns_buffer_position(rrset)); res = EVP_VerifyFinal(&ctx, sig, (unsigned int) siglen, key); EVP_MD_CTX_cleanup(&ctx); if (res == 1) { return LDNS_STATUS_OK; } else if (res == 0) { return LDNS_STATUS_CRYPTO_BOGUS; } /* TODO how to communicate internal SSL error? let caller use ssl's get_error() */ return LDNS_STATUS_SSL_ERR; } ldns_status ldns_verify_rrsig_dsa(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key) { return ldns_verify_rrsig_dsa_raw( (unsigned char*) ldns_buffer_begin(sig), ldns_buffer_position(sig), rrset, (unsigned char*) ldns_buffer_begin(key), ldns_buffer_position(key)); } ldns_status ldns_verify_rrsig_rsasha1(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key) { return ldns_verify_rrsig_rsasha1_raw( (unsigned char*)ldns_buffer_begin(sig), ldns_buffer_position(sig), rrset, (unsigned char*) ldns_buffer_begin(key), ldns_buffer_position(key)); } ldns_status ldns_verify_rrsig_rsamd5(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key) { return ldns_verify_rrsig_rsamd5_raw( (unsigned char*)ldns_buffer_begin(sig), ldns_buffer_position(sig), rrset, (unsigned char*) ldns_buffer_begin(key), ldns_buffer_position(key)); } ldns_status ldns_verify_rrsig_dsa_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen) { EVP_PKEY *evp_key; ldns_status result; evp_key = EVP_PKEY_new(); if (EVP_PKEY_assign_DSA(evp_key, ldns_key_buf2dsa_raw(key, keylen))) { result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key, EVP_dss1()); } else { result = LDNS_STATUS_SSL_ERR; } EVP_PKEY_free(evp_key); return result; } ldns_status ldns_verify_rrsig_rsasha1_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen) { EVP_PKEY *evp_key; ldns_status result; evp_key = EVP_PKEY_new(); if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) { result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key, EVP_sha1()); } else { result = LDNS_STATUS_SSL_ERR; } EVP_PKEY_free(evp_key); return result; } ldns_status ldns_verify_rrsig_rsasha256_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen) { #ifdef USE_SHA2 EVP_PKEY *evp_key; ldns_status result; evp_key = EVP_PKEY_new(); if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) { result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key, EVP_sha256()); } else { result = LDNS_STATUS_SSL_ERR; } EVP_PKEY_free(evp_key); return result; #else /* touch these to prevent compiler warnings */ (void) sig; (void) siglen; (void) rrset; (void) key; (void) keylen; return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO; #endif } ldns_status ldns_verify_rrsig_rsasha512_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen) { #ifdef USE_SHA2 EVP_PKEY *evp_key; ldns_status result; evp_key = EVP_PKEY_new(); if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) { result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key, EVP_sha512()); } else { result = LDNS_STATUS_SSL_ERR; } EVP_PKEY_free(evp_key); return result; #else /* touch these to prevent compiler warnings */ (void) sig; (void) siglen; (void) rrset; (void) key; (void) keylen; return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO; #endif } ldns_status ldns_verify_rrsig_rsamd5_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen) { EVP_PKEY *evp_key; ldns_status result; evp_key = EVP_PKEY_new(); if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) { result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key, EVP_md5()); } else { result = LDNS_STATUS_SSL_ERR; } EVP_PKEY_free(evp_key); return result; } #endif Net-LDNS-0.75/src/ldns/dnssec_zone.c000644 000770 000024 00000067471 12471046240 017540 0ustar00calledstaff000000 000000 /* * special zone file structures and functions for better dnssec handling */ #include #include ldns_dnssec_rrs * ldns_dnssec_rrs_new(void) { ldns_dnssec_rrs *new_rrs; new_rrs = LDNS_MALLOC(ldns_dnssec_rrs); if(!new_rrs) return NULL; new_rrs->rr = NULL; new_rrs->next = NULL; return new_rrs; } INLINE void ldns_dnssec_rrs_free_internal(ldns_dnssec_rrs *rrs, int deep) { ldns_dnssec_rrs *next; while (rrs) { next = rrs->next; if (deep) { ldns_rr_free(rrs->rr); } LDNS_FREE(rrs); rrs = next; } } void ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs) { ldns_dnssec_rrs_free_internal(rrs, 0); } void ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs) { ldns_dnssec_rrs_free_internal(rrs, 1); } ldns_status ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr) { int cmp; ldns_dnssec_rrs *new_rrs; if (!rrs || !rr) { return LDNS_STATUS_ERR; } /* this could be done more efficiently; name and type should already be equal */ cmp = ldns_rr_compare(rrs->rr, rr); if (cmp < 0) { if (rrs->next) { return ldns_dnssec_rrs_add_rr(rrs->next, rr); } else { new_rrs = ldns_dnssec_rrs_new(); new_rrs->rr = rr; rrs->next = new_rrs; } } else if (cmp > 0) { /* put the current old rr in the new next, put the new rr in the current container */ new_rrs = ldns_dnssec_rrs_new(); new_rrs->rr = rrs->rr; new_rrs->next = rrs->next; rrs->rr = rr; rrs->next = new_rrs; } /* Silently ignore equal rr's */ return LDNS_STATUS_OK; } void ldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_rrs *rrs) { if (!rrs) { if ((fmt->flags & LDNS_COMMENT_LAYOUT)) fprintf(out, "; "); } else { if (rrs->rr) { ldns_rr_print_fmt(out, fmt, rrs->rr); } if (rrs->next) { ldns_dnssec_rrs_print_fmt(out, fmt, rrs->next); } } } void ldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs) { ldns_dnssec_rrs_print_fmt(out, ldns_output_format_default, rrs); } ldns_dnssec_rrsets * ldns_dnssec_rrsets_new(void) { ldns_dnssec_rrsets *new_rrsets; new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets); if(!new_rrsets) return NULL; new_rrsets->rrs = NULL; new_rrsets->type = 0; new_rrsets->signatures = NULL; new_rrsets->next = NULL; return new_rrsets; } INLINE void ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep) { if (rrsets) { if (rrsets->rrs) { ldns_dnssec_rrs_free_internal(rrsets->rrs, deep); } if (rrsets->next) { ldns_dnssec_rrsets_free_internal(rrsets->next, deep); } if (rrsets->signatures) { ldns_dnssec_rrs_free_internal(rrsets->signatures, deep); } LDNS_FREE(rrsets); } } void ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets) { ldns_dnssec_rrsets_free_internal(rrsets, 0); } void ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets) { ldns_dnssec_rrsets_free_internal(rrsets, 1); } ldns_rr_type ldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets) { if (rrsets) { return rrsets->type; } else { return 0; } } ldns_status ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets, ldns_rr_type type) { if (rrsets) { rrsets->type = type; return LDNS_STATUS_OK; } return LDNS_STATUS_ERR; } static ldns_dnssec_rrsets * ldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr) { ldns_dnssec_rrsets *new_rrsets; ldns_rr_type rr_type; bool rrsig; new_rrsets = ldns_dnssec_rrsets_new(); rr_type = ldns_rr_get_type(rr); if (rr_type == LDNS_RR_TYPE_RRSIG) { rrsig = true; rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); } else { rrsig = false; } if (!rrsig) { new_rrsets->rrs = ldns_dnssec_rrs_new(); new_rrsets->rrs->rr = rr; } else { new_rrsets->signatures = ldns_dnssec_rrs_new(); new_rrsets->signatures->rr = rr; } new_rrsets->type = rr_type; return new_rrsets; } ldns_status ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr) { ldns_dnssec_rrsets *new_rrsets; ldns_rr_type rr_type; bool rrsig = false; ldns_status result = LDNS_STATUS_OK; if (!rrsets || !rr) { return LDNS_STATUS_ERR; } rr_type = ldns_rr_get_type(rr); if (rr_type == LDNS_RR_TYPE_RRSIG) { rrsig = true; rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); } if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) { if (!rrsig) { rrsets->rrs = ldns_dnssec_rrs_new(); rrsets->rrs->rr = rr; rrsets->type = rr_type; } else { rrsets->signatures = ldns_dnssec_rrs_new(); rrsets->signatures->rr = rr; rrsets->type = rr_type; } return LDNS_STATUS_OK; } if (rr_type > ldns_dnssec_rrsets_type(rrsets)) { if (rrsets->next) { result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr); } else { new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr); rrsets->next = new_rrsets; } } else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) { /* move the current one into the new next, replace field of current with data from new rr */ new_rrsets = ldns_dnssec_rrsets_new(); new_rrsets->rrs = rrsets->rrs; new_rrsets->type = rrsets->type; new_rrsets->signatures = rrsets->signatures; new_rrsets->next = rrsets->next; if (!rrsig) { rrsets->rrs = ldns_dnssec_rrs_new(); rrsets->rrs->rr = rr; rrsets->signatures = NULL; } else { rrsets->rrs = NULL; rrsets->signatures = ldns_dnssec_rrs_new(); rrsets->signatures->rr = rr; } rrsets->type = rr_type; rrsets->next = new_rrsets; } else { /* equal, add to current rrsets */ if (rrsig) { if (rrsets->signatures) { result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr); } else { rrsets->signatures = ldns_dnssec_rrs_new(); rrsets->signatures->rr = rr; } } else { if (rrsets->rrs) { result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr); } else { rrsets->rrs = ldns_dnssec_rrs_new(); rrsets->rrs->rr = rr; } } } return result; } static void ldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_rrsets *rrsets, bool follow, bool show_soa) { if (!rrsets) { if ((fmt->flags & LDNS_COMMENT_LAYOUT)) fprintf(out, "; \n"); } else { if (rrsets->rrs && (show_soa || ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA ) ) { ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->rrs); if (rrsets->signatures) { ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->signatures); } } if (follow && rrsets->next) { ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets->next, follow, show_soa); } } } void ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_rrsets *rrsets, bool follow) { ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true); } void ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow) { ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default, rrsets, follow); } ldns_dnssec_name * ldns_dnssec_name_new(void) { ldns_dnssec_name *new_name; new_name = LDNS_CALLOC(ldns_dnssec_name, 1); if (!new_name) { return NULL; } /* * not needed anymore because CALLOC initalizes everything to zero. new_name->name = NULL; new_name->rrsets = NULL; new_name->name_alloced = false; new_name->nsec = NULL; new_name->nsec_signatures = NULL; new_name->is_glue = false; new_name->hashed_name = NULL; */ return new_name; } ldns_dnssec_name * ldns_dnssec_name_new_frm_rr(ldns_rr *rr) { ldns_dnssec_name *new_name = ldns_dnssec_name_new(); new_name->name = ldns_rr_owner(rr); if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) { ldns_dnssec_name_free(new_name); return NULL; } return new_name; } INLINE void ldns_dnssec_name_free_internal(ldns_dnssec_name *name, int deep) { if (name) { if (name->name_alloced) { ldns_rdf_deep_free(name->name); } if (name->rrsets) { ldns_dnssec_rrsets_free_internal(name->rrsets, deep); } if (name->nsec && deep) { ldns_rr_free(name->nsec); } if (name->nsec_signatures) { ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep); } if (name->hashed_name) { if (deep) { ldns_rdf_deep_free(name->hashed_name); } } LDNS_FREE(name); } } void ldns_dnssec_name_free(ldns_dnssec_name *name) { ldns_dnssec_name_free_internal(name, 0); } void ldns_dnssec_name_deep_free(ldns_dnssec_name *name) { ldns_dnssec_name_free_internal(name, 1); } ldns_rdf * ldns_dnssec_name_name(ldns_dnssec_name *name) { if (name) { return name->name; } return NULL; } bool ldns_dnssec_name_is_glue(ldns_dnssec_name *name) { if (name) { return name->is_glue; } return false; } void ldns_dnssec_name_set_name(ldns_dnssec_name *rrset, ldns_rdf *dname) { if (rrset && dname) { rrset->name = dname; } } void ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec) { if (rrset && nsec) { rrset->nsec = nsec; } } int ldns_dnssec_name_cmp(const void *a, const void *b) { ldns_dnssec_name *na = (ldns_dnssec_name *) a; ldns_dnssec_name *nb = (ldns_dnssec_name *) b; if (na && nb) { return ldns_dname_compare(ldns_dnssec_name_name(na), ldns_dnssec_name_name(nb)); } else if (na) { return 1; } else if (nb) { return -1; } else { return 0; } } ldns_status ldns_dnssec_name_add_rr(ldns_dnssec_name *name, ldns_rr *rr) { ldns_status result = LDNS_STATUS_OK; ldns_rr_type rr_type; ldns_rr_type typecovered = 0; /* special handling for NSEC3 and NSECX covering RRSIGS */ if (!name || !rr) { return LDNS_STATUS_ERR; } rr_type = ldns_rr_get_type(rr); if (rr_type == LDNS_RR_TYPE_RRSIG) { typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); } if (rr_type == LDNS_RR_TYPE_NSEC || rr_type == LDNS_RR_TYPE_NSEC3) { /* XX check if is already set (and error?) */ name->nsec = rr; } else if (typecovered == LDNS_RR_TYPE_NSEC || typecovered == LDNS_RR_TYPE_NSEC3) { if (name->nsec_signatures) { result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr); } else { name->nsec_signatures = ldns_dnssec_rrs_new(); name->nsec_signatures->rr = rr; } } else { /* it's a 'normal' RR, add it to the right rrset */ if (name->rrsets) { result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr); } else { name->rrsets = ldns_dnssec_rrsets_new(); result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr); } } return result; } ldns_dnssec_rrsets * ldns_dnssec_name_find_rrset(ldns_dnssec_name *name, ldns_rr_type type) { ldns_dnssec_rrsets *result; result = name->rrsets; while (result) { if (result->type == type) { return result; } else { result = result->next; } } return NULL; } ldns_dnssec_rrsets * ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone, ldns_rdf *dname, ldns_rr_type type) { ldns_rbnode_t *node; if (!zone || !dname || !zone->names) { return NULL; } node = ldns_rbtree_search(zone->names, dname); if (node) { return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data, type); } else { return NULL; } } static void ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_name *name, bool show_soa) { if (name) { if(name->rrsets) { ldns_dnssec_rrsets_print_soa_fmt(out, fmt, name->rrsets, true, show_soa); } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { fprintf(out, ";; Empty nonterminal: "); ldns_rdf_print(out, name->name); fprintf(out, "\n"); } if(name->nsec) { ldns_rr_print_fmt(out, fmt, name->nsec); } if (name->nsec_signatures) { ldns_dnssec_rrs_print_fmt(out, fmt, name->nsec_signatures); } } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { fprintf(out, "; \n"); } } void ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_name *name) { ldns_dnssec_name_print_soa_fmt(out, fmt, name, true); } void ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name) { ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name); } ldns_dnssec_zone * ldns_dnssec_zone_new(void) { ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone); if(!zone) return NULL; zone->soa = NULL; zone->names = NULL; zone->hashed_names = NULL; zone->_nsec3params = NULL; return zone; } static bool rr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t) { return ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG && ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t; } /* When the zone is first read into an list and then inserted into an * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next) * to each other. Because ldns-verify-zone (the only program that uses this * function) uses the rbtree mostly for sequentual walking, this results * in a speed increase (of 15% on linux) because we have less CPU-cache misses. */ #define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */ static ldns_status ldns_dnssec_zone_add_empty_nonterminals_nsec3( ldns_dnssec_zone *zone, ldns_rbtree_t *nsec3s); static void ldns_todo_nsec3_ents_node_free(ldns_rbnode_t *node, void *arg) { (void) arg; ldns_rdf_deep_free((ldns_rdf *)node->key); LDNS_FREE(node); } ldns_status ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr) { ldns_rr* cur_rr; size_t i; ldns_rdf *my_origin = NULL; ldns_rdf *my_prev = NULL; ldns_dnssec_zone *newzone = ldns_dnssec_zone_new(); /* NSEC3s may occur before the names they refer to. We must remember them and add them to the name later on, after the name is read. We track not yet matching NSEC3s*n the todo_nsec3s list */ ldns_rr_list* todo_nsec3s = ldns_rr_list_new(); /* when reading NSEC3s, there is a chance that we encounter nsecs for empty nonterminals, whose nonterminals we cannot derive yet because the needed information is to be read later. nsec3_ents (where ent is e.n.t.; i.e. empty non terminal) will hold the NSEC3s that still didn't have a matching name in the zone tree, even after all names were read. They can only match after the zone is equiped with all the empty non terminals. */ ldns_rbtree_t todo_nsec3_ents; ldns_rbnode_t *new_node; ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new(); ldns_status status; #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP ldns_zone* zone = NULL; #else uint32_t my_ttl = ttl; #endif ldns_rbtree_init(&todo_nsec3_ents, ldns_dname_compare_v); #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP status = ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr); if (status != LDNS_STATUS_OK) goto error; #endif if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) { status = LDNS_STATUS_MEM_ERR; goto error; } if (origin) { if (!(my_origin = ldns_rdf_clone(origin))) { status = LDNS_STATUS_MEM_ERR; goto error; } if (!(my_prev = ldns_rdf_clone(origin))) { status = LDNS_STATUS_MEM_ERR; goto error; } } #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP if (ldns_zone_soa(zone)) { status = ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone)); if (status != LDNS_STATUS_OK) goto error; } for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) { cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i); status = LDNS_STATUS_OK; #else while (!feof(fp)) { status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin, &my_prev, line_nr); #endif switch (status) { case LDNS_STATUS_OK: status = ldns_dnssec_zone_add_rr(newzone, cur_rr); if (status == LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) { if (rr_is_rrsig_covering(cur_rr, LDNS_RR_TYPE_NSEC3)){ ldns_rr_list_push_rr(todo_nsec3_rrsigs, cur_rr); } else { ldns_rr_list_push_rr(todo_nsec3s, cur_rr); } status = LDNS_STATUS_OK; } else if (status != LDNS_STATUS_OK) goto error; break; case LDNS_STATUS_SYNTAX_EMPTY: /* empty line was seen */ case LDNS_STATUS_SYNTAX_TTL: /* the ttl was set*/ case LDNS_STATUS_SYNTAX_ORIGIN: /* the origin was set*/ status = LDNS_STATUS_OK; break; case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */ status = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL; break; default: goto error; } } for (i = 0; status == LDNS_STATUS_OK && i < ldns_rr_list_rr_count(todo_nsec3s); i++) { cur_rr = ldns_rr_list_rr(todo_nsec3s, i); status = ldns_dnssec_zone_add_rr(newzone, cur_rr); if (status == LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) { if (!(new_node = LDNS_MALLOC(ldns_rbnode_t))) { status = LDNS_STATUS_MEM_ERR; break; } new_node->key = ldns_dname_label(ldns_rr_owner(cur_rr), 0); new_node->data = cur_rr; if (!ldns_rbtree_insert(&todo_nsec3_ents, new_node)) { LDNS_FREE(new_node); status = LDNS_STATUS_MEM_ERR; break; } status = LDNS_STATUS_OK; } } if (todo_nsec3_ents.count > 0) (void) ldns_dnssec_zone_add_empty_nonterminals_nsec3( newzone, &todo_nsec3_ents); for (i = 0; status == LDNS_STATUS_OK && i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); i++) { cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i); status = ldns_dnssec_zone_add_rr(newzone, cur_rr); } if (z) { *z = newzone; newzone = NULL; } else { ldns_dnssec_zone_free(newzone); } error: #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP if (zone) { ldns_zone_free(zone); } #endif ldns_rr_list_free(todo_nsec3_rrsigs); ldns_traverse_postorder(&todo_nsec3_ents, ldns_todo_nsec3_ents_node_free, NULL); ldns_rr_list_free(todo_nsec3s); if (my_origin) { ldns_rdf_deep_free(my_origin); } if (my_prev) { ldns_rdf_deep_free(my_prev); } if (newzone) { ldns_dnssec_zone_free(newzone); } return status; } ldns_status ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, uint32_t ttl, ldns_rr_class ATTR_UNUSED(c)) { return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL); } static void ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) { (void) arg; ldns_dnssec_name_free((ldns_dnssec_name *)node->data); LDNS_FREE(node); } static void ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) { (void) arg; ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data); LDNS_FREE(node); } void ldns_dnssec_zone_free(ldns_dnssec_zone *zone) { if (zone) { if (zone->names) { /* destroy all name structures within the tree */ ldns_traverse_postorder(zone->names, ldns_dnssec_name_node_free, NULL); LDNS_FREE(zone->names); } LDNS_FREE(zone); } } void ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone) { if (zone) { if (zone->names) { /* destroy all name structures within the tree */ ldns_traverse_postorder(zone->names, ldns_dnssec_name_node_deep_free, NULL); LDNS_FREE(zone->names); } LDNS_FREE(zone); } } /* use for dname comparison in tree */ int ldns_dname_compare_v(const void *a, const void *b) { return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b); } static void ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone, ldns_dnssec_name* name, ldns_rr* nsec3rr); static void ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) { (void) arg; LDNS_FREE(node); } static void ldns_dnssec_zone_hashed_names_from_nsec3( ldns_dnssec_zone* zone, ldns_rr* nsec3rr) { ldns_rbnode_t* current_node; ldns_dnssec_name* current_name; assert(zone != NULL); assert(nsec3rr != NULL); if (zone->hashed_names) { ldns_traverse_postorder(zone->hashed_names, ldns_hashed_names_node_free, NULL); LDNS_FREE(zone->hashed_names); } zone->_nsec3params = nsec3rr; /* So this is a NSEC3 zone. * Calculate hashes for all names already in the zone */ zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v); if (zone->hashed_names == NULL) { return; } for ( current_node = ldns_rbtree_first(zone->names) ; current_node != LDNS_RBTREE_NULL ; current_node = ldns_rbtree_next(current_node) ) { current_name = (ldns_dnssec_name *) current_node->data; ldns_dnssec_name_make_hashed_name(zone, current_name, nsec3rr); } } static void ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone, ldns_dnssec_name* name, ldns_rr* nsec3rr) { ldns_rbnode_t* new_node; assert(name != NULL); if (! zone->_nsec3params) { if (! nsec3rr) { return; } ldns_dnssec_zone_hashed_names_from_nsec3(zone, nsec3rr); } else if (! nsec3rr) { nsec3rr = zone->_nsec3params; } name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsec3rr, name->name); /* Also store in zone->hashed_names */ if ((new_node = LDNS_MALLOC(ldns_rbnode_t))) { new_node->key = name->hashed_name; new_node->data = name; if (ldns_rbtree_insert(zone->hashed_names, new_node) == NULL) { LDNS_FREE(new_node); } } } static ldns_rbnode_t * ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, ldns_rr *rr) { ldns_rdf *hashed_name; hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0); if (hashed_name == NULL) { return NULL; } if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 && ! zone->_nsec3params){ ldns_dnssec_zone_hashed_names_from_nsec3(zone, rr); } if (zone->hashed_names == NULL) { ldns_rdf_deep_free(hashed_name); return NULL; } return ldns_rbtree_search(zone->hashed_names, hashed_name); } ldns_status ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr) { ldns_status result = LDNS_STATUS_OK; ldns_dnssec_name *cur_name; ldns_rbnode_t *cur_node; ldns_rr_type type_covered = 0; if (!zone || !rr) { return LDNS_STATUS_ERR; } if (!zone->names) { zone->names = ldns_rbtree_create(ldns_dname_compare_v); if(!zone->names) return LDNS_STATUS_MEM_ERR; } /* we need the original of the hashed name if this is an NSEC3, or an RRSIG that covers an NSEC3 */ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) { type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); } if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 || type_covered == LDNS_RR_TYPE_NSEC3) { cur_node = ldns_dnssec_zone_find_nsec3_original(zone, rr); if (!cur_node) { return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND; } } else { cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr)); } if (!cur_node) { /* add */ cur_name = ldns_dnssec_name_new_frm_rr(rr); if(!cur_name) return LDNS_STATUS_MEM_ERR; cur_node = LDNS_MALLOC(ldns_rbnode_t); if(!cur_node) { ldns_dnssec_name_free(cur_name); return LDNS_STATUS_MEM_ERR; } cur_node->key = ldns_rr_owner(rr); cur_node->data = cur_name; (void)ldns_rbtree_insert(zone->names, cur_node); ldns_dnssec_name_make_hashed_name(zone, cur_name, NULL); } else { cur_name = (ldns_dnssec_name *) cur_node->data; result = ldns_dnssec_name_add_rr(cur_name, rr); } if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { zone->soa = cur_name; } return result; } void ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_rbtree_t *tree, bool print_soa) { ldns_rbnode_t *node; ldns_dnssec_name *name; node = ldns_rbtree_first(tree); while (node != LDNS_RBTREE_NULL) { name = (ldns_dnssec_name *) node->data; ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa); if ((fmt->flags & LDNS_COMMENT_LAYOUT)) fprintf(out, ";\n"); node = ldns_rbtree_next(node); } } void ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa) { ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default, tree, print_soa); } void ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_zone *zone) { if (zone) { if (zone->soa) { if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { fprintf(out, ";; Zone: "); ldns_rdf_print(out, ldns_dnssec_name_name( zone->soa)); fprintf(out, "\n;\n"); } ldns_dnssec_rrsets_print_fmt(out, fmt, ldns_dnssec_name_find_rrset( zone->soa, LDNS_RR_TYPE_SOA), false); if ((fmt->flags & LDNS_COMMENT_LAYOUT)) fprintf(out, ";\n"); } if (zone->names) { ldns_dnssec_zone_names_print_fmt(out, fmt, zone->names, false); } } } void ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone) { ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone); } static ldns_status ldns_dnssec_zone_add_empty_nonterminals_nsec3( ldns_dnssec_zone *zone, ldns_rbtree_t *nsec3s) { ldns_dnssec_name *new_name; ldns_rdf *cur_name; ldns_rdf *next_name; ldns_rbnode_t *cur_node, *next_node, *new_node; /* for the detection */ uint16_t i, cur_label_count, next_label_count; uint16_t soa_label_count = 0; ldns_rdf *l1, *l2; int lpos; if (!zone) { return LDNS_STATUS_ERR; } if (zone->soa && zone->soa->name) { soa_label_count = ldns_dname_label_count(zone->soa->name); } cur_node = ldns_rbtree_first(zone->names); while (cur_node != LDNS_RBTREE_NULL) { next_node = ldns_rbtree_next(cur_node); /* skip glue */ while (next_node != LDNS_RBTREE_NULL && next_node->data && ((ldns_dnssec_name *)next_node->data)->is_glue ) { next_node = ldns_rbtree_next(next_node); } if (next_node == LDNS_RBTREE_NULL) { next_node = ldns_rbtree_first(zone->names); } if (! cur_node->data || ! next_node->data) { return LDNS_STATUS_ERR; } cur_name = ((ldns_dnssec_name *)cur_node->data)->name; next_name = ((ldns_dnssec_name *)next_node->data)->name; cur_label_count = ldns_dname_label_count(cur_name); next_label_count = ldns_dname_label_count(next_name); /* Since the names are in canonical order, we can * recognize empty non-terminals by their labels; * every label after the first one on the next owner * name is a non-terminal if it either does not exist * in the current name or is different from the same * label in the current name (counting from the end) */ for (i = 1; i < next_label_count - soa_label_count; i++) { lpos = (int)cur_label_count - (int)next_label_count + (int)i; if (lpos >= 0) { l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos); } else { l1 = NULL; } l2 = ldns_dname_clone_from(next_name, i); if (!l1 || ldns_dname_compare(l1, l2) != 0) { /* We have an empty nonterminal, add it to the * tree */ ldns_rbnode_t *node = NULL; ldns_rdf *ent_name; if (!(ent_name = ldns_dname_clone_from( next_name, i))) return LDNS_STATUS_MEM_ERR; if (nsec3s && zone->_nsec3params) { ldns_rdf *ent_hashed_name; if (!(ent_hashed_name = ldns_nsec3_hash_name_frm_nsec3( zone->_nsec3params, ent_name))) return LDNS_STATUS_MEM_ERR; node = ldns_rbtree_search(nsec3s, ent_hashed_name); if (!node) { ldns_rdf_deep_free(l1); ldns_rdf_deep_free(l2); continue; } } new_name = ldns_dnssec_name_new(); if (!new_name) { return LDNS_STATUS_MEM_ERR; } new_name->name = ent_name; if (!new_name->name) { ldns_dnssec_name_free(new_name); return LDNS_STATUS_MEM_ERR; } new_name->name_alloced = true; new_node = LDNS_MALLOC(ldns_rbnode_t); if (!new_node) { ldns_dnssec_name_free(new_name); return LDNS_STATUS_MEM_ERR; } new_node->key = new_name->name; new_node->data = new_name; (void)ldns_rbtree_insert(zone->names, new_node); ldns_dnssec_name_make_hashed_name( zone, new_name, NULL); if (node) (void) ldns_dnssec_zone_add_rr(zone, (ldns_rr *)node->data); } ldns_rdf_deep_free(l1); ldns_rdf_deep_free(l2); } /* we might have inserted a new node after * the current one so we can't just use next() */ if (next_node != ldns_rbtree_first(zone->names)) { cur_node = next_node; } else { cur_node = LDNS_RBTREE_NULL; } } return LDNS_STATUS_OK; } ldns_status ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone) { return ldns_dnssec_zone_add_empty_nonterminals_nsec3(zone, NULL); } bool ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone) { ldns_rr* nsec3; ldns_rbnode_t* node; if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) { node = ldns_rbtree_first(zone->names); while (node != LDNS_RBTREE_NULL) { nsec3 = ((ldns_dnssec_name*)node->data)->nsec; if (nsec3 &&ldns_rr_get_type(nsec3) == LDNS_RR_TYPE_NSEC3 && ldns_nsec3_optout(nsec3)) { return true; } node = ldns_rbtree_next(node); } } return false; } Net-LDNS-0.75/src/ldns/duration.c000644 000770 000024 00000021152 12471046240 017035 0ustar00calledstaff000000 000000 /* * $Id: duration.c 4518 2011-02-24 15:39:09Z matthijs $ * * Copyright (c) 2009 NLNet Labs. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * * This file is copied from the OpenDNSSEC source repository * and only slightly adapted to make it fit. */ /** * * Durations. */ #include #include #include #include #include #include /** * Create a new 'instant' duration. * */ ldns_duration_type* ldns_duration_create(void) { ldns_duration_type* duration; duration = malloc(sizeof(ldns_duration_type)); if (!duration) { return NULL; } duration->years = 0; duration->months = 0; duration->weeks = 0; duration->days = 0; duration->hours = 0; duration->minutes = 0; duration->seconds = 0; return duration; } /** * Compare durations. * */ int ldns_duration_compare(ldns_duration_type* d1, ldns_duration_type* d2) { if (!d1 && !d2) { return 0; } if (!d1 || !d2) { return d1?-1:1; } if (d1->years != d2->years) { return (int) (d1->years - d2->years); } if (d1->months != d2->months) { return (int) (d1->months - d2->months); } if (d1->weeks != d2->weeks) { return (int) (d1->weeks - d2->weeks); } if (d1->days != d2->days) { return (int) (d1->days - d2->days); } if (d1->hours != d2->hours) { return (int) (d1->hours - d2->hours); } if (d1->minutes != d2->minutes) { return (int) (d1->minutes - d2->minutes); } if (d1->seconds != d2->seconds) { return (int) (d1->seconds - d2->seconds); } return 0; } /** * Create a duration from string. * */ ldns_duration_type* ldns_duration_create_from_string(const char* str) { ldns_duration_type* duration = ldns_duration_create(); char* P, *X, *T, *W; int not_weeks = 0; if (!duration) { return NULL; } if (!str) { return duration; } P = strchr(str, 'P'); if (!P) { ldns_duration_cleanup(duration); return NULL; } T = strchr(str, 'T'); X = strchr(str, 'Y'); if (X) { duration->years = (time_t) atoi(str+1); str = X; not_weeks = 1; } X = strchr(str, 'M'); if (X && (!T || (size_t) (X-P) < (size_t) (T-P))) { duration->months = (time_t) atoi(str+1); str = X; not_weeks = 1; } X = strchr(str, 'D'); if (X) { duration->days = (time_t) atoi(str+1); str = X; not_weeks = 1; } if (T) { str = T; not_weeks = 1; } X = strchr(str, 'H'); if (X && T) { duration->hours = (time_t) atoi(str+1); str = X; not_weeks = 1; } X = strrchr(str, 'M'); if (X && T && (size_t) (X-P) > (size_t) (T-P)) { duration->minutes = (time_t) atoi(str+1); str = X; not_weeks = 1; } X = strchr(str, 'S'); if (X && T) { duration->seconds = (time_t) atoi(str+1); str = X; not_weeks = 1; } W = strchr(str, 'W'); if (W) { if (not_weeks) { ldns_duration_cleanup(duration); return NULL; } else { duration->weeks = (time_t) atoi(str+1); str = W; } } return duration; } /** * Get the number of digits in a number. * */ static size_t digits_in_number(time_t duration) { uint32_t period = (uint32_t) duration; size_t count = 0; while (period > 0) { count++; period /= 10; } return count; } /** * Convert a duration to a string. * */ char* ldns_duration2string(ldns_duration_type* duration) { char* str = NULL, *num = NULL; size_t count = 2; int T = 0; if (!duration) { return NULL; } if (duration->years > 0) { count = count + 1 + digits_in_number(duration->years); } if (duration->months > 0) { count = count + 1 + digits_in_number(duration->months); } if (duration->weeks > 0) { count = count + 1 + digits_in_number(duration->weeks); } if (duration->days > 0) { count = count + 1 + digits_in_number(duration->days); } if (duration->hours > 0) { count = count + 1 + digits_in_number(duration->hours); T = 1; } if (duration->minutes > 0) { count = count + 1 + digits_in_number(duration->minutes); T = 1; } if (duration->seconds > 0) { count = count + 1 + digits_in_number(duration->seconds); T = 1; } if (T) { count++; } str = (char*) calloc(count, sizeof(char)); str[0] = 'P'; str[1] = '\0'; if (duration->years > 0) { count = digits_in_number(duration->years); num = (char*) calloc(count+2, sizeof(char)); snprintf(num, count+2, "%uY", (unsigned int) duration->years); str = strncat(str, num, count+2); free((void*) num); } if (duration->months > 0) { count = digits_in_number(duration->months); num = (char*) calloc(count+2, sizeof(char)); snprintf(num, count+2, "%uM", (unsigned int) duration->months); str = strncat(str, num, count+2); free((void*) num); } if (duration->weeks > 0) { count = digits_in_number(duration->weeks); num = (char*) calloc(count+2, sizeof(char)); snprintf(num, count+2, "%uW", (unsigned int) duration->weeks); str = strncat(str, num, count+2); free((void*) num); } if (duration->days > 0) { count = digits_in_number(duration->days); num = (char*) calloc(count+2, sizeof(char)); snprintf(num, count+2, "%uD", (unsigned int) duration->days); str = strncat(str, num, count+2); free((void*) num); } if (T) { str = strncat(str, "T", 1); } if (duration->hours > 0) { count = digits_in_number(duration->hours); num = (char*) calloc(count+2, sizeof(char)); snprintf(num, count+2, "%uH", (unsigned int) duration->hours); str = strncat(str, num, count+2); free((void*) num); } if (duration->minutes > 0) { count = digits_in_number(duration->minutes); num = (char*) calloc(count+2, sizeof(char)); snprintf(num, count+2, "%uM", (unsigned int) duration->minutes); str = strncat(str, num, count+2); free((void*) num); } if (duration->seconds > 0) { count = digits_in_number(duration->seconds); num = (char*) calloc(count+2, sizeof(char)); snprintf(num, count+2, "%uS", (unsigned int) duration->seconds); str = strncat(str, num, count+2); free((void*) num); } return str; } /** * Convert a duration to a time. * */ time_t ldns_duration2time(ldns_duration_type* duration) { time_t period = 0; if (duration) { period += (duration->seconds); period += (duration->minutes)*60; period += (duration->hours)*3600; period += (duration->days)*86400; period += (duration->weeks)*86400*7; period += (duration->months)*86400*31; period += (duration->years)*86400*365; /* [TODO] calculate correct number of days in this month/year */ /* if (duration->months || duration->years) { } */ } return period; } /** * Clean up duration. * */ void ldns_duration_cleanup(ldns_duration_type* duration) { if (!duration) { return; } free(duration); return; } Net-LDNS-0.75/src/ldns/error.c000644 000770 000024 00000021576 12471046240 016353 0ustar00calledstaff000000 000000 /* * a error2str function to make sense of all the * error codes we have laying ardoun * * a Net::DNS like library for C * LibDNS Team @ NLnet Labs * (c) NLnet Labs, 2005-2006 * See the file LICENSE for the license */ #include #include ldns_lookup_table ldns_error_str[] = { { LDNS_STATUS_OK, "All OK" }, { LDNS_STATUS_EMPTY_LABEL, "Empty label" }, { LDNS_STATUS_LABEL_OVERFLOW, "Label length overflow" }, { LDNS_STATUS_DOMAINNAME_OVERFLOW, "Domainname length overflow" }, { LDNS_STATUS_DOMAINNAME_UNDERFLOW, "Domainname length underflow (zero length)" }, { LDNS_STATUS_DDD_OVERFLOW, "\\DDD sequence overflow (>255)" }, { LDNS_STATUS_PACKET_OVERFLOW, "Packet size overflow" }, { LDNS_STATUS_INVALID_POINTER, "Invalid compression pointer" }, { LDNS_STATUS_MEM_ERR, "General memory error" }, { LDNS_STATUS_INTERNAL_ERR, "Internal error, this should not happen" }, { LDNS_STATUS_SSL_ERR, "Error in SSL library" }, { LDNS_STATUS_ERR, "General LDNS error" }, { LDNS_STATUS_INVALID_INT, "Conversion error, integer expected" }, { LDNS_STATUS_INVALID_IP4, "Conversion error, ip4 addr expected" }, { LDNS_STATUS_INVALID_IP6, "Conversion error, ip6 addr expected" }, { LDNS_STATUS_INVALID_STR, "Conversion error, string expected" }, { LDNS_STATUS_INVALID_B32_EXT, "Conversion error, b32 ext encoding expected" }, { LDNS_STATUS_INVALID_B64, "Conversion error, b64 encoding expected" }, { LDNS_STATUS_INVALID_HEX, "Conversion error, hex encoding expected" }, { LDNS_STATUS_INVALID_TIME, "Conversion error, time encoding expected" }, { LDNS_STATUS_NETWORK_ERR, "Could not send or receive, because of network error" }, { LDNS_STATUS_ADDRESS_ERR, "Could not start AXFR, because of address error" }, { LDNS_STATUS_FILE_ERR, "Could not open the files" }, { LDNS_STATUS_UNKNOWN_INET, "Uknown address family" }, { LDNS_STATUS_NOT_IMPL, "This function is not implemented (yet), please notify the developers - or not..." }, { LDNS_STATUS_NULL, "Supplied value pointer null" }, { LDNS_STATUS_CRYPTO_UNKNOWN_ALGO, "Unknown cryptographic algorithm" }, { LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL, "Cryptographic algorithm not implemented" }, { LDNS_STATUS_CRYPTO_NO_RRSIG, "No DNSSEC signature(s)" }, { LDNS_STATUS_CRYPTO_NO_DNSKEY, "No DNSSEC public key(s)" }, { LDNS_STATUS_CRYPTO_TYPE_COVERED_ERR, "The signature does not cover this RRset" }, { LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY, "No signatures found for trusted DNSSEC public key(s)" }, { LDNS_STATUS_CRYPTO_NO_DS, "No DS record(s)" }, { LDNS_STATUS_CRYPTO_NO_TRUSTED_DS, "Could not validate DS record(s)" }, { LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY, "No keys with the keytag and algorithm from the RRSIG found" }, { LDNS_STATUS_CRYPTO_VALIDATED, "Valid DNSSEC signature" }, { LDNS_STATUS_CRYPTO_BOGUS, "Bogus DNSSEC signature" }, { LDNS_STATUS_CRYPTO_SIG_EXPIRED, "DNSSEC signature has expired" }, { LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED, "DNSSEC signature not incepted yet" }, { LDNS_STATUS_CRYPTO_TSIG_BOGUS, "Bogus TSIG signature" }, { LDNS_STATUS_CRYPTO_TSIG_ERR, "Could not create TSIG signature" }, { LDNS_STATUS_CRYPTO_EXPIRATION_BEFORE_INCEPTION, "DNSSEC signature has expiration date earlier than inception date" }, { LDNS_STATUS_ENGINE_KEY_NOT_LOADED, "Unable to load private key from engine" }, { LDNS_STATUS_NSEC3_ERR, "Error in NSEC3 denial of existence proof" }, { LDNS_STATUS_RES_NO_NS, "No (valid) nameservers defined in the resolver" }, { LDNS_STATUS_RES_QUERY, "No correct query given to resolver" }, { LDNS_STATUS_WIRE_INCOMPLETE_HEADER, "header section incomplete" }, { LDNS_STATUS_WIRE_INCOMPLETE_QUESTION, "question section incomplete" }, { LDNS_STATUS_WIRE_INCOMPLETE_ANSWER, "answer section incomplete" }, { LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY, "authority section incomplete" }, { LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL, "additional section incomplete" }, { LDNS_STATUS_NO_DATA, "No data" }, { LDNS_STATUS_EXISTS_ERR, "Element already exists" }, { LDNS_STATUS_CERT_BAD_ALGORITHM, "Bad algorithm type for CERT record" }, { LDNS_STATUS_SYNTAX_TYPE_ERR, "Syntax error, could not parse the RR's type" }, { LDNS_STATUS_SYNTAX_CLASS_ERR, "Syntax error, could not parse the RR's class" }, { LDNS_STATUS_SYNTAX_TTL_ERR, "Syntax error, could not parse the RR's TTL" }, { LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL, "Syntax error, $INCLUDE not implemented" }, { LDNS_STATUS_SYNTAX_RDATA_ERR, "Syntax error, could not parse the RR's rdata" }, { LDNS_STATUS_SYNTAX_DNAME_ERR, "Syntax error, could not parse the RR's dname(s)" }, { LDNS_STATUS_SYNTAX_VERSION_ERR, "Syntax error, version mismatch" }, { LDNS_STATUS_SYNTAX_ALG_ERR, "Syntax error, algorithm unknown or non parseable" }, { LDNS_STATUS_SYNTAX_KEYWORD_ERR, "Syntax error, unknown keyword in input" }, { LDNS_STATUS_SYNTAX_ERR, "Syntax error, could not parse the RR" }, { LDNS_STATUS_SYNTAX_EMPTY, "Empty line was returned" }, { LDNS_STATUS_SYNTAX_TTL, "$TTL directive was seen in the zone" }, { LDNS_STATUS_SYNTAX_ORIGIN, "$ORIGIN directive was seen in the zone" }, { LDNS_STATUS_SYNTAX_INCLUDE, "$INCLUDE directive was seen in the zone" }, { LDNS_STATUS_SYNTAX_ITERATIONS_OVERFLOW, "Iterations count for NSEC3 record higher than maximum" }, { LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR, "Syntax error, value expected" }, { LDNS_STATUS_SYNTAX_INTEGER_OVERFLOW, "Syntax error, integer value too large" }, { LDNS_STATUS_SYNTAX_BAD_ESCAPE, "Syntax error, bad escape sequence" }, { LDNS_STATUS_SOCKET_ERROR, "Error creating socket" }, { LDNS_STATUS_DNSSEC_EXISTENCE_DENIED, "Existence denied by NSEC" }, { LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED, "RR not covered by the given NSEC RRs" }, { LDNS_STATUS_DNSSEC_NSEC_WILDCARD_NOT_COVERED, "wildcard not covered by the given NSEC RRs" }, { LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND, "original of NSEC3 hashed name could not be found" }, { LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG, "The RRSIG has to few rdata fields" }, { LDNS_STATUS_MISSING_RDATA_FIELDS_KEY, "The DNSKEY has to few rdata fields" }, { LDNS_STATUS_CRYPTO_SIG_EXPIRED_WITHIN_MARGIN, "DNSSEC signature will expire too soon" }, { LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED_WITHIN_MARGIN, "DNSSEC signature not incepted long enough" }, { LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE, "Unknown TLSA Certificate Usage" }, { LDNS_STATUS_DANE_UNKNOWN_SELECTOR, "Unknown TLSA Selector" }, { LDNS_STATUS_DANE_UNKNOWN_MATCHING_TYPE, "Unknown TLSA Matching Type" }, { LDNS_STATUS_DANE_UNKNOWN_PROTOCOL, "Unknown protocol. Only IPv4 and IPv6 are understood" }, { LDNS_STATUS_DANE_UNKNOWN_TRANSPORT, "Unknown transport. Should be one of {tcp, udp, sctp}" }, { LDNS_STATUS_DANE_MISSING_EXTRA_CERTS, /* Trust anchor assertion */ "More than one certificate should be provided" }, { LDNS_STATUS_DANE_EXTRA_CERTS_NOT_USED, /* Trust anchor assertion */ "Non of the extra certificates is used to sign the first" }, { LDNS_STATUS_DANE_OFFSET_OUT_OF_RANGE, /* Trust anchor assertion */ "The offset was out of range" }, { LDNS_STATUS_DANE_INSECURE, /* Unused by library */ "The queried resource records were insecure" }, { LDNS_STATUS_DANE_BOGUS, /* Unused by library */ "The queried resource records were bogus" }, { LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH, "The TLSA record(s) " "did not match with the server certificate (chain)" }, { LDNS_STATUS_DANE_NON_CA_CERTIFICATE, "The certificate was not a CA certificate" }, { LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE, "Could not PKIX validate" }, { LDNS_STATUS_DANE_PKIX_NO_SELF_SIGNED_TRUST_ANCHOR, "The validation path " "did not end in a self-signed certificate" }, { LDNS_STATUS_INVALID_ILNP64, "Conversion error, 4 colon separated hex numbers expected" }, { LDNS_STATUS_INVALID_EUI48, "Conversion error, 6 two character hex numbers " "separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx" }, { LDNS_STATUS_INVALID_EUI64, "Conversion error, 8 two character hex numbers " "separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx-xx-xx" }, { LDNS_STATUS_WIRE_RDATA_ERR, "invalid rdata in wire format" }, { LDNS_STATUS_INVALID_TAG, "Conversion error, a non-zero sequence of US-ASCII letters " "and numbers in lower case expected" }, { LDNS_STATUS_TYPE_NOT_IN_BITMAP, "The RR type bitmap rdata field did not have " "a bit reserved for the specific RR type" }, { LDNS_STATUS_INVALID_RDF_TYPE, "The rdata field was not of the expected type" }, { LDNS_STATUS_RDATA_OVERFLOW, "Rdata size overflow" }, { 0, NULL } }; const char * ldns_get_errorstr_by_id(ldns_status err) { ldns_lookup_table *lt; lt = ldns_lookup_by_id(ldns_error_str, err); if (lt) { return lt->name; } return NULL; } Net-LDNS-0.75/src/ldns/higher.c000644 000770 000024 00000016721 12471046240 016464 0ustar00calledstaff000000 000000 /* * higher.c * * Specify some higher level functions that would * be usefull to would be developers * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include #ifdef HAVE_SSL #include #include #endif /* HAVE_SSL */ ldns_rr_list * ldns_get_rr_list_addr_by_name(ldns_resolver *res, ldns_rdf *name, ldns_rr_class c, uint16_t flags) { ldns_pkt *pkt; ldns_rr_list *aaaa; ldns_rr_list *a; ldns_rr_list *result = NULL; ldns_rr_list *hostsfilenames; size_t i; uint8_t ip6; a = NULL; aaaa = NULL; result = NULL; if (!res) { return NULL; } if (ldns_rdf_get_type(name) != LDNS_RDF_TYPE_DNAME) { return NULL; } ip6 = ldns_resolver_ip6(res); /* we use INET_ANY here, save what was there */ ldns_resolver_set_ip6(res, LDNS_RESOLV_INETANY); hostsfilenames = ldns_get_rr_list_hosts_frm_file(NULL); for (i = 0; i < ldns_rr_list_rr_count(hostsfilenames); i++) { if (ldns_rdf_compare(name, ldns_rr_owner(ldns_rr_list_rr(hostsfilenames, i))) == 0) { if (!result) { result = ldns_rr_list_new(); } ldns_rr_list_push_rr(result, ldns_rr_clone(ldns_rr_list_rr(hostsfilenames, i))); } } ldns_rr_list_deep_free(hostsfilenames); if (result) { return result; } /* add the RD flags, because we want an answer */ pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_AAAA, c, flags | LDNS_RD); if (pkt) { /* extract the data we need */ aaaa = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_AAAA, LDNS_SECTION_ANSWER); ldns_pkt_free(pkt); } pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_A, c, flags | LDNS_RD); if (pkt) { /* extract the data we need */ a = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_A, LDNS_SECTION_ANSWER); ldns_pkt_free(pkt); } ldns_resolver_set_ip6(res, ip6); if (aaaa && a) { result = ldns_rr_list_cat_clone(aaaa, a); ldns_rr_list_deep_free(aaaa); ldns_rr_list_deep_free(a); return result; } if (aaaa) { result = ldns_rr_list_clone(aaaa); } if (a) { result = ldns_rr_list_clone(a); } ldns_rr_list_deep_free(aaaa); ldns_rr_list_deep_free(a); return result; } ldns_rr_list * ldns_get_rr_list_name_by_addr(ldns_resolver *res, ldns_rdf *addr, ldns_rr_class c, uint16_t flags) { ldns_pkt *pkt; ldns_rr_list *names; ldns_rdf *name; names = NULL; if (!res || !addr) { return NULL; } if (ldns_rdf_get_type(addr) != LDNS_RDF_TYPE_A && ldns_rdf_get_type(addr) != LDNS_RDF_TYPE_AAAA) { return NULL; } name = ldns_rdf_address_reverse(addr); /* add the RD flags, because we want an answer */ pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_PTR, c, flags | LDNS_RD); ldns_rdf_deep_free(name); if (pkt) { /* extract the data we need */ names = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_PTR, LDNS_SECTION_ANSWER); ldns_pkt_free(pkt); } return names; } /* read a line, put it in a buffer, parse the buffer */ ldns_rr_list * ldns_get_rr_list_hosts_frm_fp(FILE *fp) { return ldns_get_rr_list_hosts_frm_fp_l(fp, NULL); } ldns_rr_list * ldns_get_rr_list_hosts_frm_fp_l(FILE *fp, int *line_nr) { ssize_t i, j; size_t cnt; char *line; char *word; char *addr; char *rr_str; ldns_buffer *linebuf; ldns_rr *rr; ldns_rr_list *list; ldns_rdf *tmp; bool ip6; ldns_status parse_result; line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1); word = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1); addr = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1); rr_str = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1); ip6 = false; list = ldns_rr_list_new(); rr = NULL; if(!line || !word || !addr || !rr_str || !list) { LDNS_FREE(line); LDNS_FREE(word); LDNS_FREE(addr); LDNS_FREE(rr_str); ldns_rr_list_free(list); return NULL; } for(i = ldns_fget_token_l(fp, line, "\n", LDNS_MAX_LINELEN, line_nr); i > 0; i = ldns_fget_token_l(fp, line, "\n", LDNS_MAX_LINELEN, line_nr)) { /* # is comment */ if (line[0] == '#') { continue; } /* put it in a buffer for further processing */ linebuf = LDNS_MALLOC(ldns_buffer); if(!linebuf) { LDNS_FREE(line); LDNS_FREE(word); LDNS_FREE(addr); LDNS_FREE(rr_str); ldns_rr_list_deep_free(list); return NULL; } ldns_buffer_new_frm_data(linebuf, line, (size_t) i); for(cnt = 0, j = ldns_bget_token(linebuf, word, LDNS_PARSE_NO_NL, LDNS_MAX_LINELEN); j > 0; j = ldns_bget_token(linebuf, word, LDNS_PARSE_NO_NL, LDNS_MAX_LINELEN), cnt++) { if (cnt == 0) { /* the address */ if ((tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, word))) { /* ip6 */ ldns_rdf_deep_free(tmp); ip6 = true; } else { if ((tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, word))) { /* ip4 */ ldns_rdf_deep_free(tmp); ip6 = false; } else { /* kaput */ break; } } (void)strlcpy(addr, word, LDNS_MAX_LINELEN+1); } else { /* la al la la */ if (ip6) { snprintf(rr_str, LDNS_MAX_LINELEN, "%s IN AAAA %s", word, addr); } else { snprintf(rr_str, LDNS_MAX_LINELEN, "%s IN A %s", word, addr); } parse_result = ldns_rr_new_frm_str(&rr, rr_str, 0, NULL, NULL); if (parse_result == LDNS_STATUS_OK && ldns_rr_owner(rr) && ldns_rr_rd_count(rr) > 0) { ldns_rr_list_push_rr(list, ldns_rr_clone(rr)); } ldns_rr_free(rr); } } ldns_buffer_free(linebuf); } LDNS_FREE(line); LDNS_FREE(word); LDNS_FREE(addr); LDNS_FREE(rr_str); return list; } ldns_rr_list * ldns_get_rr_list_hosts_frm_file(char *filename) { ldns_rr_list *names; FILE *fp; if (!filename) { fp = fopen(LDNS_RESOLV_HOSTS, "r"); } else { fp = fopen(filename, "r"); } if (!fp) { return NULL; } names = ldns_get_rr_list_hosts_frm_fp(fp); fclose(fp); return names; } uint16_t ldns_getaddrinfo(ldns_resolver *res, ldns_rdf *node, ldns_rr_class c, ldns_rr_list **ret) { ldns_rdf_type t; uint16_t names_found; ldns_resolver *r; ldns_status s; t = ldns_rdf_get_type(node); names_found = 0; r = res; if (res == NULL) { /* prepare a new resolver, using /etc/resolv.conf as a guide */ s = ldns_resolver_new_frm_file(&r, NULL); if (s != LDNS_STATUS_OK) { return 0; } } if (t == LDNS_RDF_TYPE_DNAME) { /* we're asked to query for a name */ *ret = ldns_get_rr_list_addr_by_name(r, node, c, 0); names_found = ldns_rr_list_rr_count(*ret); } if (t == LDNS_RDF_TYPE_A || t == LDNS_RDF_TYPE_AAAA) { /* an address */ *ret = ldns_get_rr_list_name_by_addr(r, node, c, 0); names_found = ldns_rr_list_rr_count(*ret); } if (res == NULL) { ldns_resolver_deep_free(r); } return names_found; } bool ldns_nsec_type_check(ldns_rr *nsec, ldns_rr_type t) { switch (ldns_rr_get_type(nsec)) { case LDNS_RR_TYPE_NSEC : if (ldns_rr_rd_count(nsec) < 2) { return false; } return ldns_nsec_bitmap_covers_type( ldns_rr_rdf(nsec, 1), t); case LDNS_RR_TYPE_NSEC3 : if (ldns_rr_rd_count(nsec) < 6) { return false; } return ldns_nsec_bitmap_covers_type( ldns_rr_rdf(nsec, 5), t); default : return false; } } void ldns_print_rr_rdf(FILE *fp, ldns_rr *r, int rdfnum, ...) { int16_t rdf; ldns_rdf *rd; va_list va_rdf; va_start(va_rdf, rdfnum); for (rdf = (int16_t)rdfnum; rdf != -1; rdf = (int16_t)va_arg(va_rdf, int)) { rd = ldns_rr_rdf(r, rdf); if (!rd) { continue; } else { ldns_rdf_print(fp, rd); fprintf(fp, " "); /* not sure if we want to do this */ } } va_end(va_rdf); } Net-LDNS-0.75/src/ldns/host2str.c000644 000770 000024 00000212563 12471046240 017010 0ustar00calledstaff000000 000000 /* * host2str.c * * conversion routines from the host format * to the presentation format (strings) * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #include #include #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 #endif #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 #endif /* lookup tables for standard DNS stuff */ /* Taken from RFC 2535, section 7. */ ldns_lookup_table ldns_algorithms[] = { { LDNS_RSAMD5, "RSAMD5" }, { LDNS_DH, "DH" }, { LDNS_DSA, "DSA" }, { LDNS_ECC, "ECC" }, { LDNS_RSASHA1, "RSASHA1" }, { LDNS_DSA_NSEC3, "DSA-NSEC3-SHA1" }, { LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" }, #ifdef USE_SHA2 { LDNS_RSASHA256, "RSASHA256"}, { LDNS_RSASHA512, "RSASHA512"}, #endif #ifdef USE_GOST { LDNS_ECC_GOST, "ECC-GOST"}, #endif #ifdef USE_ECDSA { LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"}, { LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"}, #endif { LDNS_INDIRECT, "INDIRECT" }, { LDNS_PRIVATEDNS, "PRIVATEDNS" }, { LDNS_PRIVATEOID, "PRIVATEOID" }, { 0, NULL } }; /* Taken from RFC 4398 */ ldns_lookup_table ldns_cert_algorithms[] = { { LDNS_CERT_PKIX, "PKIX" }, { LDNS_CERT_SPKI, "SPKI" }, { LDNS_CERT_PGP, "PGP" }, { LDNS_CERT_IPKIX, "IPKIX" }, { LDNS_CERT_ISPKI, "ISPKI" }, { LDNS_CERT_IPGP, "IPGP" }, { LDNS_CERT_ACPKIX, "ACPKIX" }, { LDNS_CERT_IACPKIX, "IACPKIX" }, { LDNS_CERT_URI, "URI" }, { LDNS_CERT_OID, "OID" }, { 0, NULL } }; /* classes */ ldns_lookup_table ldns_rr_classes[] = { { LDNS_RR_CLASS_IN, "IN" }, { LDNS_RR_CLASS_CH, "CH" }, { LDNS_RR_CLASS_HS, "HS" }, { LDNS_RR_CLASS_NONE, "NONE" }, { LDNS_RR_CLASS_ANY, "ANY" }, { 0, NULL } }; /* if these are used elsewhere */ ldns_lookup_table ldns_rcodes[] = { { LDNS_RCODE_NOERROR, "NOERROR" }, { LDNS_RCODE_FORMERR, "FORMERR" }, { LDNS_RCODE_SERVFAIL, "SERVFAIL" }, { LDNS_RCODE_NXDOMAIN, "NXDOMAIN" }, { LDNS_RCODE_NOTIMPL, "NOTIMPL" }, { LDNS_RCODE_REFUSED, "REFUSED" }, { LDNS_RCODE_YXDOMAIN, "YXDOMAIN" }, { LDNS_RCODE_YXRRSET, "YXRRSET" }, { LDNS_RCODE_NXRRSET, "NXRRSET" }, { LDNS_RCODE_NOTAUTH, "NOTAUTH" }, { LDNS_RCODE_NOTZONE, "NOTZONE" }, { 0, NULL } }; ldns_lookup_table ldns_opcodes[] = { { LDNS_PACKET_QUERY, "QUERY" }, { LDNS_PACKET_IQUERY, "IQUERY" }, { LDNS_PACKET_STATUS, "STATUS" }, { LDNS_PACKET_NOTIFY, "NOTIFY" }, { LDNS_PACKET_UPDATE, "UPDATE" }, { 0, NULL } }; const ldns_output_format ldns_output_format_nocomments_record = { 0, NULL }; const ldns_output_format *ldns_output_format_nocomments = &ldns_output_format_nocomments_record; const ldns_output_format ldns_output_format_onlykeyids_record = { LDNS_COMMENT_KEY, NULL }; const ldns_output_format *ldns_output_format_onlykeyids = &ldns_output_format_onlykeyids_record; const ldns_output_format *ldns_output_format_default = &ldns_output_format_onlykeyids_record; const ldns_output_format ldns_output_format_bubblebabble_record = { LDNS_COMMENT_KEY | LDNS_COMMENT_BUBBLEBABBLE | LDNS_COMMENT_FLAGS, NULL }; const ldns_output_format *ldns_output_format_bubblebabble = &ldns_output_format_bubblebabble_record; static bool ldns_output_format_covers_type(const ldns_output_format* fmt, ldns_rr_type t) { return fmt && (fmt->flags & LDNS_FMT_RFC3597) && ((ldns_output_format_storage*)fmt)->bitmap && ldns_nsec_bitmap_covers_type( ((ldns_output_format_storage*)fmt)->bitmap, t); } ldns_status ldns_output_format_set_type(ldns_output_format* fmt, ldns_rr_type t) { ldns_output_format_storage* fmt_st = (ldns_output_format_storage*)fmt; ldns_status s; assert(fmt != NULL); if (!(fmt_st->flags & LDNS_FMT_RFC3597)) { ldns_output_format_set(fmt, LDNS_FMT_RFC3597); } if (! fmt_st->bitmap) { s = ldns_rdf_bitmap_known_rr_types_space(&fmt_st->bitmap); if (s != LDNS_STATUS_OK) { return s; } } return ldns_nsec_bitmap_set_type(fmt_st->bitmap, t); } ldns_status ldns_output_format_clear_type(ldns_output_format* fmt, ldns_rr_type t) { ldns_output_format_storage* fmt_st = (ldns_output_format_storage*)fmt; ldns_status s; assert(fmt != NULL); if (!(fmt_st->flags & LDNS_FMT_RFC3597)) { ldns_output_format_set(fmt, LDNS_FMT_RFC3597); } if (! fmt_st->bitmap) { s = ldns_rdf_bitmap_known_rr_types(&fmt_st->bitmap); if (s != LDNS_STATUS_OK) { return s; } } return ldns_nsec_bitmap_clear_type(fmt_st->bitmap, t); } ldns_status ldns_pkt_opcode2buffer_str(ldns_buffer *output, ldns_pkt_opcode opcode) { ldns_lookup_table *lt = ldns_lookup_by_id(ldns_opcodes, opcode); if (lt && lt->name) { ldns_buffer_printf(output, "%s", lt->name); } else { ldns_buffer_printf(output, "OPCODE%u", opcode); } return ldns_buffer_status(output); } ldns_status ldns_pkt_rcode2buffer_str(ldns_buffer *output, ldns_pkt_rcode rcode) { ldns_lookup_table *lt = ldns_lookup_by_id(ldns_rcodes, rcode); if (lt && lt->name) { ldns_buffer_printf(output, "%s", lt->name); } else { ldns_buffer_printf(output, "RCODE%u", rcode); } return ldns_buffer_status(output); } ldns_status ldns_algorithm2buffer_str(ldns_buffer *output, ldns_algorithm algorithm) { ldns_lookup_table *lt = ldns_lookup_by_id(ldns_algorithms, algorithm); if (lt && lt->name) { ldns_buffer_printf(output, "%s", lt->name); } else { ldns_buffer_printf(output, "ALG%u", algorithm); } return ldns_buffer_status(output); } ldns_status ldns_cert_algorithm2buffer_str(ldns_buffer *output, ldns_cert_algorithm cert_algorithm) { ldns_lookup_table *lt = ldns_lookup_by_id(ldns_cert_algorithms, cert_algorithm); if (lt && lt->name) { ldns_buffer_printf(output, "%s", lt->name); } else { ldns_buffer_printf(output, "CERT_ALG%u", cert_algorithm); } return ldns_buffer_status(output); } char * ldns_pkt_opcode2str(ldns_pkt_opcode opcode) { char *str; ldns_buffer *buf; buf = ldns_buffer_new(12); if (!buf) { return NULL; } str = NULL; if (ldns_pkt_opcode2buffer_str(buf, opcode) == LDNS_STATUS_OK) { str = ldns_buffer_export2str(buf); } ldns_buffer_free(buf); return str; } char * ldns_pkt_rcode2str(ldns_pkt_rcode rcode) { char *str; ldns_buffer *buf; buf = ldns_buffer_new(10); if (!buf) { return NULL; } str = NULL; if (ldns_pkt_rcode2buffer_str(buf, rcode) == LDNS_STATUS_OK) { str = ldns_buffer_export2str(buf); } ldns_buffer_free(buf); return str; } char * ldns_pkt_algorithm2str(ldns_algorithm algorithm) { char *str; ldns_buffer *buf; buf = ldns_buffer_new(10); if (!buf) { return NULL; } str = NULL; if (ldns_algorithm2buffer_str(buf, algorithm) == LDNS_STATUS_OK) { str = ldns_buffer_export2str(buf); } ldns_buffer_free(buf); return str; } char * ldns_pkt_cert_algorithm2str(ldns_cert_algorithm cert_algorithm) { char *str; ldns_buffer *buf; buf = ldns_buffer_new(10); if (!buf) { return NULL; } str = NULL; if (ldns_cert_algorithm2buffer_str(buf, cert_algorithm) == LDNS_STATUS_OK) { str = ldns_buffer_export2str(buf); } ldns_buffer_free(buf); return str; } /* do NOT pass compressed data here :p */ ldns_status ldns_rdf2buffer_str_dname(ldns_buffer *output, const ldns_rdf *dname) { /* can we do with 1 pos var? or without at all? */ uint8_t src_pos = 0; uint8_t len; uint8_t *data; uint8_t i; unsigned char c; data = (uint8_t*)ldns_rdf_data(dname); len = data[src_pos]; if (ldns_rdf_size(dname) > LDNS_MAX_DOMAINLEN) { /* too large, return */ return LDNS_STATUS_DOMAINNAME_OVERFLOW; } /* special case: root label */ if (1 == ldns_rdf_size(dname)) { ldns_buffer_printf(output, "."); } else { while ((len > 0) && src_pos < ldns_rdf_size(dname)) { src_pos++; for(i = 0; i < len; i++) { /* paranoia check for various 'strange' characters in dnames */ c = (unsigned char) data[src_pos]; if(c == '.' || c == ';' || c == '(' || c == ')' || c == '\\') { ldns_buffer_printf(output, "\\%c", data[src_pos]); } else if (!(isascii(c) && isgraph(c))) { ldns_buffer_printf(output, "\\%03u", data[src_pos]); } else { ldns_buffer_printf(output, "%c", data[src_pos]); } src_pos++; } if (src_pos < ldns_rdf_size(dname)) { ldns_buffer_printf(output, "."); } len = data[src_pos]; } } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_int8(ldns_buffer *output, const ldns_rdf *rdf) { uint8_t data = ldns_rdf_data(rdf)[0]; ldns_buffer_printf(output, "%lu", (unsigned long) data); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_int16(ldns_buffer *output, const ldns_rdf *rdf) { uint16_t data = ldns_read_uint16(ldns_rdf_data(rdf)); ldns_buffer_printf(output, "%lu", (unsigned long) data); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_int32(ldns_buffer *output, const ldns_rdf *rdf) { uint32_t data = ldns_read_uint32(ldns_rdf_data(rdf)); ldns_buffer_printf(output, "%lu", (unsigned long) data); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_time(ldns_buffer *output, const ldns_rdf *rdf) { /* create a YYYYMMDDHHMMSS string if possible */ struct tm tm; char date_buf[16]; memset(&tm, 0, sizeof(tm)); if (ldns_serial_arithmitics_gmtime_r(ldns_rdf2native_int32(rdf), time(NULL), &tm) && strftime(date_buf, 15, "%Y%m%d%H%M%S", &tm)) { ldns_buffer_printf(output, "%s", date_buf); } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_a(ldns_buffer *output, const ldns_rdf *rdf) { char str[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, ldns_rdf_data(rdf), str, INET_ADDRSTRLEN)) { ldns_buffer_printf(output, "%s", str); } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_aaaa(ldns_buffer *output, const ldns_rdf *rdf) { char str[INET6_ADDRSTRLEN]; if (inet_ntop(AF_INET6, ldns_rdf_data(rdf), str, INET6_ADDRSTRLEN)) { ldns_buffer_printf(output, "%s", str); } return ldns_buffer_status(output); } static void ldns_characters2buffer_str(ldns_buffer* output, size_t amount, const uint8_t* characters) { uint8_t ch; while (amount > 0) { ch = *characters++; if (isprint((int)ch) || ch == '\t') { if (ch == '\"' || ch == '\\') ldns_buffer_printf(output, "\\%c", ch); else ldns_buffer_printf(output, "%c", ch); } else { ldns_buffer_printf(output, "\\%03u", (unsigned)(uint8_t) ch); } amount--; } } ldns_status ldns_rdf2buffer_str_str(ldns_buffer *output, const ldns_rdf *rdf) { if(ldns_rdf_size(rdf) < 1) { return LDNS_STATUS_WIRE_RDATA_ERR; } if((int)ldns_rdf_size(rdf) < (int)ldns_rdf_data(rdf)[0] + 1) { return LDNS_STATUS_WIRE_RDATA_ERR; } ldns_buffer_printf(output, "\""); ldns_characters2buffer_str(output, ldns_rdf_data(rdf)[0], ldns_rdf_data(rdf) + 1); ldns_buffer_printf(output, "\""); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_b64(ldns_buffer *output, const ldns_rdf *rdf) { size_t size = ldns_b64_ntop_calculate_size(ldns_rdf_size(rdf)); char *b64 = LDNS_XMALLOC(char, size); if(!b64) return LDNS_STATUS_MEM_ERR; if (ldns_b64_ntop(ldns_rdf_data(rdf), ldns_rdf_size(rdf), b64, size)) { ldns_buffer_printf(output, "%s", b64); } LDNS_FREE(b64); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_b32_ext(ldns_buffer *output, const ldns_rdf *rdf) { size_t size; char *b32; if(ldns_rdf_size(rdf) == 0) return LDNS_STATUS_OK; /* remove -1 for the b32-hash-len octet */ size = ldns_b32_ntop_calculate_size(ldns_rdf_size(rdf) - 1); /* add one for the end nul for the string */ b32 = LDNS_XMALLOC(char, size + 1); if(!b32) return LDNS_STATUS_MEM_ERR; size = (size_t) ldns_b32_ntop_extended_hex(ldns_rdf_data(rdf) + 1, ldns_rdf_size(rdf) - 1, b32, size+1); if (size > 0) { ldns_buffer_printf(output, "%s", b32); } LDNS_FREE(b32); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_hex(ldns_buffer *output, const ldns_rdf *rdf) { size_t i; for (i = 0; i < ldns_rdf_size(rdf); i++) { ldns_buffer_printf(output, "%02x", ldns_rdf_data(rdf)[i]); } return ldns_buffer_status(output); } static ldns_status ldns_rdf2buffer_str_type_fmt(ldns_buffer *output, const ldns_output_format* fmt, const ldns_rdf *rdf) { uint16_t data = ldns_read_uint16(ldns_rdf_data(rdf)); if (! ldns_output_format_covers_type(fmt, data) && ldns_rr_descript(data) && ldns_rr_descript(data)->_name) { ldns_buffer_printf(output, "%s",ldns_rr_descript(data)->_name); } else { ldns_buffer_printf(output, "TYPE%u", data); } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_type(ldns_buffer *output, const ldns_rdf *rdf) { return ldns_rdf2buffer_str_type_fmt(output, ldns_output_format_default, rdf); } ldns_status ldns_rdf2buffer_str_class(ldns_buffer *output, const ldns_rdf *rdf) { uint16_t data = ldns_read_uint16(ldns_rdf_data(rdf)); ldns_lookup_table *lt; lt = ldns_lookup_by_id(ldns_rr_classes, (int) data); if (lt) { ldns_buffer_printf(output, "\t%s", lt->name); } else { ldns_buffer_printf(output, "\tCLASS%d", data); } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_cert_alg(ldns_buffer *output, const ldns_rdf *rdf) { uint16_t data = ldns_read_uint16(ldns_rdf_data(rdf)); ldns_lookup_table *lt; lt = ldns_lookup_by_id(ldns_cert_algorithms, (int) data); if (lt) { ldns_buffer_printf(output, "%s", lt->name); } else { ldns_buffer_printf(output, "%d", data); } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_alg(ldns_buffer *output, const ldns_rdf *rdf) { return ldns_rdf2buffer_str_int8(output, rdf); } static void loc_cm_print(ldns_buffer *output, uint8_t mantissa, uint8_t exponent) { uint8_t i; /* is it 0. ? */ if(exponent < 2) { if(exponent == 1) mantissa *= 10; ldns_buffer_printf(output, "0.%02ld", (long)mantissa); return; } /* always */ ldns_buffer_printf(output, "%d", (int)mantissa); for(i=0; i_name) { ldns_buffer_printf(output, "%s", descriptor->_name); } else { ldns_buffer_printf(output, "TYPE%u", type); } } return ldns_buffer_status(output); } char * ldns_rr_type2str(const ldns_rr_type type) { char *str; ldns_buffer *buf; buf = ldns_buffer_new(10); if (!buf) { return NULL; } str = NULL; if (ldns_rr_type2buffer_str(buf, type) == LDNS_STATUS_OK) { str = ldns_buffer_export2str(buf); } ldns_buffer_free(buf); return str; } ldns_status ldns_rr_class2buffer_str(ldns_buffer *output, const ldns_rr_class klass) { ldns_lookup_table *lt; lt = ldns_lookup_by_id(ldns_rr_classes, klass); if (lt) { ldns_buffer_printf(output, "%s", lt->name); } else { ldns_buffer_printf(output, "CLASS%d", klass); } return ldns_buffer_status(output); } char * ldns_rr_class2str(const ldns_rr_class klass) { ldns_buffer *buf; char *str; buf = ldns_buffer_new(10); if (!buf) { return NULL; } str = NULL; if (ldns_rr_class2buffer_str(buf, klass) == LDNS_STATUS_OK) { str = ldns_buffer_export2str(buf); } ldns_buffer_free(buf); return str; } ldns_status ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf) { /* we could do checking (ie degrees < 90 etc)? */ uint8_t version; uint8_t size; uint8_t horizontal_precision; uint8_t vertical_precision; uint32_t longitude; uint32_t latitude; uint32_t altitude; char northerness; char easterness; uint32_t h; uint32_t m; double s; uint32_t equator = (uint32_t) ldns_power(2, 31); if(ldns_rdf_size(rdf) < 1) { return LDNS_STATUS_WIRE_RDATA_ERR; } version = ldns_rdf_data(rdf)[0]; if (version == 0) { if(ldns_rdf_size(rdf) < 16) { return LDNS_STATUS_WIRE_RDATA_ERR; } size = ldns_rdf_data(rdf)[1]; horizontal_precision = ldns_rdf_data(rdf)[2]; vertical_precision = ldns_rdf_data(rdf)[3]; latitude = ldns_read_uint32(&ldns_rdf_data(rdf)[4]); longitude = ldns_read_uint32(&ldns_rdf_data(rdf)[8]); altitude = ldns_read_uint32(&ldns_rdf_data(rdf)[12]); if (latitude > equator) { northerness = 'N'; latitude = latitude - equator; } else { northerness = 'S'; latitude = equator - latitude; } h = latitude / (1000 * 60 * 60); latitude = latitude % (1000 * 60 * 60); m = latitude / (1000 * 60); latitude = latitude % (1000 * 60); s = (double) latitude / 1000.0; ldns_buffer_printf(output, "%02u %02u %0.3f %c ", h, m, s, northerness); if (longitude > equator) { easterness = 'E'; longitude = longitude - equator; } else { easterness = 'W'; longitude = equator - longitude; } h = longitude / (1000 * 60 * 60); longitude = longitude % (1000 * 60 * 60); m = longitude / (1000 * 60); longitude = longitude % (1000 * 60); s = (double) longitude / (1000.0); ldns_buffer_printf(output, "%02u %02u %0.3f %c ", h, m, s, easterness); s = ((double) altitude) / 100; s -= 100000; if(altitude%100 != 0) ldns_buffer_printf(output, "%.2f", s); else ldns_buffer_printf(output, "%.0f", s); ldns_buffer_printf(output, "m "); loc_cm_print(output, (size & 0xf0) >> 4, size & 0x0f); ldns_buffer_printf(output, "m "); loc_cm_print(output, (horizontal_precision & 0xf0) >> 4, horizontal_precision & 0x0f); ldns_buffer_printf(output, "m "); loc_cm_print(output, (vertical_precision & 0xf0) >> 4, vertical_precision & 0x0f); ldns_buffer_printf(output, "m"); return ldns_buffer_status(output); } else { return ldns_rdf2buffer_str_hex(output, rdf); } } ldns_status ldns_rdf2buffer_str_unknown(ldns_buffer *output, const ldns_rdf *rdf) { ldns_buffer_printf(output, "\\# %u ", ldns_rdf_size(rdf)); return ldns_rdf2buffer_str_hex(output, rdf); } ldns_status ldns_rdf2buffer_str_nsap(ldns_buffer *output, const ldns_rdf *rdf) { ldns_buffer_printf(output, "0x"); return ldns_rdf2buffer_str_hex(output, rdf); } ldns_status ldns_rdf2buffer_str_atma(ldns_buffer *output, const ldns_rdf *rdf) { return ldns_rdf2buffer_str_hex(output, rdf); } ldns_status ldns_rdf2buffer_str_wks(ldns_buffer *output, const ldns_rdf *rdf) { /* protocol, followed by bitmap of services */ struct protoent *protocol; char *proto_name = NULL; uint8_t protocol_nr; struct servent *service; uint16_t current_service; if(ldns_rdf_size(rdf) < 1) { return LDNS_STATUS_WIRE_RDATA_ERR; } protocol_nr = ldns_rdf_data(rdf)[0]; protocol = getprotobynumber((int) protocol_nr); if (protocol && (protocol->p_name != NULL)) { proto_name = protocol->p_name; ldns_buffer_printf(output, "%s ", protocol->p_name); } else { ldns_buffer_printf(output, "%u ", protocol_nr); } #ifdef HAVE_ENDPROTOENT endprotoent(); #endif for (current_service = 0; current_service < (ldns_rdf_size(rdf)-1)*8; current_service++) { if (ldns_get_bit(&(ldns_rdf_data(rdf)[1]), current_service)) { service = getservbyport((int) htons(current_service), proto_name); if (service && service->s_name) { ldns_buffer_printf(output, "%s ", service->s_name); } else { ldns_buffer_printf(output, "%u ", current_service); } #ifdef HAVE_ENDSERVENT endservent(); #endif } } return ldns_buffer_status(output); } static ldns_status ldns_rdf2buffer_str_nsec_fmt(ldns_buffer *output, const ldns_output_format* fmt, const ldns_rdf *rdf) { /* Note: this code is duplicated in higher.c in * ldns_nsec_type_check() function */ uint8_t window_block_nr; uint8_t bitmap_length; uint16_t type; uint16_t pos = 0; uint16_t bit_pos; uint8_t *data = ldns_rdf_data(rdf); while((size_t)(pos + 2) < ldns_rdf_size(rdf)) { window_block_nr = data[pos]; bitmap_length = data[pos + 1]; pos += 2; if (ldns_rdf_size(rdf) < pos + bitmap_length) { return LDNS_STATUS_WIRE_RDATA_ERR; } for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) { if (! ldns_get_bit(&data[pos], bit_pos)) { continue; } type = 256 * (uint16_t) window_block_nr + bit_pos; if (! ldns_output_format_covers_type(fmt, type) && ldns_rr_descript(type) && ldns_rr_descript(type)->_name){ ldns_buffer_printf(output, "%s ", ldns_rr_descript(type)->_name); } else { ldns_buffer_printf(output, "TYPE%u ", type); } } pos += (uint16_t) bitmap_length; } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf) { return ldns_rdf2buffer_str_nsec_fmt(output, ldns_output_format_default, rdf); } ldns_status ldns_rdf2buffer_str_nsec3_salt(ldns_buffer *output, const ldns_rdf *rdf) { uint8_t salt_length; uint8_t salt_pos; uint8_t *data = ldns_rdf_data(rdf); if(ldns_rdf_size(rdf) < 1) { return LDNS_STATUS_WIRE_RDATA_ERR; } salt_length = data[0]; /* from now there are variable length entries so remember pos */ if (salt_length == 0 || ((size_t)salt_length)+1 > ldns_rdf_size(rdf)) { ldns_buffer_printf(output, "- "); } else { for (salt_pos = 0; salt_pos < salt_length; salt_pos++) { ldns_buffer_printf(output, "%02x", data[1 + salt_pos]); } ldns_buffer_printf(output, " "); } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_period(ldns_buffer *output, const ldns_rdf *rdf) { /* period is the number of seconds */ if (ldns_rdf_size(rdf) != 4) { return LDNS_STATUS_WIRE_RDATA_ERR; } ldns_buffer_printf(output, "%u", ldns_read_uint32(ldns_rdf_data(rdf))); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_tsigtime(ldns_buffer *output,const ldns_rdf *rdf) { /* tsigtime is 48 bits network order unsigned integer */ uint64_t tsigtime = 0; uint8_t *data = ldns_rdf_data(rdf); uint64_t d0, d1, d2, d3, d4, d5; if (ldns_rdf_size(rdf) < 6) { return LDNS_STATUS_WIRE_RDATA_ERR; } d0 = data[0]; /* cast to uint64 for shift operations */ d1 = data[1]; d2 = data[2]; d3 = data[3]; d4 = data[4]; d5 = data[5]; tsigtime = (d0<<40) | (d1<<32) | (d2<<24) | (d3<<16) | (d4<<8) | d5; ldns_buffer_printf(output, "%llu ", (long long)tsigtime); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_apl(ldns_buffer *output, const ldns_rdf *rdf) { uint8_t *data = ldns_rdf_data(rdf); uint16_t address_family; uint8_t prefix; bool negation; uint8_t adf_length; size_t i; size_t pos = 0; while (pos < (unsigned int) ldns_rdf_size(rdf)) { if(pos + 3 >= (unsigned)ldns_rdf_size(rdf)) return LDNS_STATUS_WIRE_RDATA_ERR; address_family = ldns_read_uint16(&data[pos]); prefix = data[pos + 2]; negation = data[pos + 3] & LDNS_APL_NEGATION; adf_length = data[pos + 3] & LDNS_APL_MASK; if (address_family == LDNS_APL_IP4) { /* check if prefix < 32? */ if (negation) { ldns_buffer_printf(output, "!"); } ldns_buffer_printf(output, "%u:", address_family); /* address is variable length 0 - 4 */ for (i = 0; i < 4; i++) { if (i > 0) { ldns_buffer_printf(output, "."); } if (i < (unsigned short) adf_length) { if(pos+i+4 >= ldns_rdf_size(rdf)) return LDNS_STATUS_WIRE_RDATA_ERR; ldns_buffer_printf(output, "%d", data[pos + i + 4]); } else { ldns_buffer_printf(output, "0"); } } ldns_buffer_printf(output, "/%u ", prefix); } else if (address_family == LDNS_APL_IP6) { /* check if prefix < 128? */ if (negation) { ldns_buffer_printf(output, "!"); } ldns_buffer_printf(output, "%u:", address_family); /* address is variable length 0 - 16 */ for (i = 0; i < 16; i++) { if (i % 2 == 0 && i > 0) { ldns_buffer_printf(output, ":"); } if (i < (unsigned short) adf_length) { if(pos+i+4 >= ldns_rdf_size(rdf)) return LDNS_STATUS_WIRE_RDATA_ERR; ldns_buffer_printf(output, "%02x", data[pos + i + 4]); } else { ldns_buffer_printf(output, "00"); } } ldns_buffer_printf(output, "/%u ", prefix); } else { /* unknown address family */ ldns_buffer_printf(output, "Unknown address family: %u data: ", address_family); for (i = 1; i < (unsigned short) (4 + adf_length); i++) { if(pos+i >= ldns_rdf_size(rdf)) return LDNS_STATUS_WIRE_RDATA_ERR; ldns_buffer_printf(output, "%02x", data[i]); } } pos += 4 + adf_length; } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_int16_data(ldns_buffer *output, const ldns_rdf *rdf) { size_t size; char *b64; if (ldns_rdf_size(rdf) < 2) { return LDNS_STATUS_WIRE_RDATA_ERR; } /* Subtract the size (2) of the number that specifies the length */ size = ldns_b64_ntop_calculate_size(ldns_rdf_size(rdf) - 2); ldns_buffer_printf(output, "%u ", ldns_rdf_size(rdf) - 2); if (ldns_rdf_size(rdf) > 2) { b64 = LDNS_XMALLOC(char, size); if(!b64) return LDNS_STATUS_MEM_ERR; if (ldns_rdf_size(rdf) > 2 && ldns_b64_ntop(ldns_rdf_data(rdf) + 2, ldns_rdf_size(rdf) - 2, b64, size)) { ldns_buffer_printf(output, "%s", b64); } LDNS_FREE(b64); } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf) { /* wire format from http://www.ietf.org/internet-drafts/draft-ietf-ipseckey-rr-12.txt */ uint8_t *data = ldns_rdf_data(rdf); uint8_t precedence; uint8_t gateway_type; uint8_t algorithm; ldns_rdf *gateway = NULL; uint8_t *gateway_data; size_t public_key_size; uint8_t *public_key_data; ldns_rdf *public_key; size_t offset = 0; ldns_status status; if (ldns_rdf_size(rdf) < 3) { return LDNS_STATUS_WIRE_RDATA_ERR; } precedence = data[0]; gateway_type = data[1]; algorithm = data[2]; offset = 3; switch (gateway_type) { case 0: /* no gateway */ break; case 1: gateway_data = LDNS_XMALLOC(uint8_t, LDNS_IP4ADDRLEN); if(!gateway_data) return LDNS_STATUS_MEM_ERR; if (ldns_rdf_size(rdf) < offset + LDNS_IP4ADDRLEN) { return LDNS_STATUS_ERR; } memcpy(gateway_data, &data[offset], LDNS_IP4ADDRLEN); gateway = ldns_rdf_new(LDNS_RDF_TYPE_A, LDNS_IP4ADDRLEN , gateway_data); offset += LDNS_IP4ADDRLEN; if(!gateway) { LDNS_FREE(gateway_data); return LDNS_STATUS_MEM_ERR; } break; case 2: gateway_data = LDNS_XMALLOC(uint8_t, LDNS_IP6ADDRLEN); if(!gateway_data) return LDNS_STATUS_MEM_ERR; if (ldns_rdf_size(rdf) < offset + LDNS_IP6ADDRLEN) { return LDNS_STATUS_ERR; } memcpy(gateway_data, &data[offset], LDNS_IP6ADDRLEN); offset += LDNS_IP6ADDRLEN; gateway = ldns_rdf_new(LDNS_RDF_TYPE_AAAA, LDNS_IP6ADDRLEN, gateway_data); if(!gateway) { LDNS_FREE(gateway_data); return LDNS_STATUS_MEM_ERR; } break; case 3: status = ldns_wire2dname(&gateway, data, ldns_rdf_size(rdf), &offset); if(status != LDNS_STATUS_OK) return status; break; default: /* error? */ break; } if (ldns_rdf_size(rdf) <= offset) { return LDNS_STATUS_ERR; } public_key_size = ldns_rdf_size(rdf) - offset; public_key_data = LDNS_XMALLOC(uint8_t, public_key_size); if(!public_key_data) { ldns_rdf_free(gateway); return LDNS_STATUS_MEM_ERR; } memcpy(public_key_data, &data[offset], public_key_size); public_key = ldns_rdf_new(LDNS_RDF_TYPE_B64, public_key_size, public_key_data); if(!public_key) { LDNS_FREE(public_key_data); ldns_rdf_free(gateway); return LDNS_STATUS_MEM_ERR; } ldns_buffer_printf(output, "%u %u %u ", precedence, gateway_type, algorithm); if (gateway) (void) ldns_rdf2buffer_str(output, gateway); else ldns_buffer_printf(output, "."); ldns_buffer_printf(output, " "); (void) ldns_rdf2buffer_str(output, public_key); ldns_rdf_free(gateway); ldns_rdf_free(public_key); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_ilnp64(ldns_buffer *output, const ldns_rdf *rdf) { if (ldns_rdf_size(rdf) != 8) { return LDNS_STATUS_WIRE_RDATA_ERR; } ldns_buffer_printf(output,"%.4x:%.4x:%.4x:%.4x", ldns_read_uint16(ldns_rdf_data(rdf)), ldns_read_uint16(ldns_rdf_data(rdf)+2), ldns_read_uint16(ldns_rdf_data(rdf)+4), ldns_read_uint16(ldns_rdf_data(rdf)+6)); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_eui48(ldns_buffer *output, const ldns_rdf *rdf) { if (ldns_rdf_size(rdf) != 6) { return LDNS_STATUS_WIRE_RDATA_ERR; } ldns_buffer_printf(output,"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", ldns_rdf_data(rdf)[0], ldns_rdf_data(rdf)[1], ldns_rdf_data(rdf)[2], ldns_rdf_data(rdf)[3], ldns_rdf_data(rdf)[4], ldns_rdf_data(rdf)[5]); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_eui64(ldns_buffer *output, const ldns_rdf *rdf) { if (ldns_rdf_size(rdf) != 8) { return LDNS_STATUS_WIRE_RDATA_ERR; } ldns_buffer_printf(output,"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", ldns_rdf_data(rdf)[0], ldns_rdf_data(rdf)[1], ldns_rdf_data(rdf)[2], ldns_rdf_data(rdf)[3], ldns_rdf_data(rdf)[4], ldns_rdf_data(rdf)[5], ldns_rdf_data(rdf)[6], ldns_rdf_data(rdf)[7]); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_tag(ldns_buffer *output, const ldns_rdf *rdf) { size_t nchars; const uint8_t* chars; char ch; if (ldns_rdf_size(rdf) < 2) { return LDNS_STATUS_WIRE_RDATA_ERR; } nchars = ldns_rdf_data(rdf)[0]; if (nchars >= ldns_rdf_size(rdf) || /* should be rdf_size - 1 */ nchars < 1) { return LDNS_STATUS_WIRE_RDATA_ERR; } chars = ldns_rdf_data(rdf) + 1; while (nchars > 0) { ch = (char)*chars++; if (! isalnum(ch)) { return LDNS_STATUS_WIRE_RDATA_ERR; } ldns_buffer_printf(output, "%c", ch); nchars--; } return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_long_str(ldns_buffer *output, const ldns_rdf *rdf) { ldns_buffer_printf(output, "\""); ldns_characters2buffer_str(output, ldns_rdf_size(rdf), ldns_rdf_data(rdf)); ldns_buffer_printf(output, "\""); return ldns_buffer_status(output); } ldns_status ldns_rdf2buffer_str_hip(ldns_buffer *output, const ldns_rdf *rdf) { uint8_t *data = ldns_rdf_data(rdf); size_t rdf_size = ldns_rdf_size(rdf); uint8_t hit_size; uint16_t pk_size; int written; if (rdf_size < 6) { return LDNS_STATUS_WIRE_RDATA_ERR; } if ((hit_size = data[0]) == 0 || (pk_size = ldns_read_uint16(data + 2)) == 0 || rdf_size < (size_t) hit_size + pk_size + 4) { return LDNS_STATUS_WIRE_RDATA_ERR; } ldns_buffer_printf(output, "%d ", (int) data[1]); for (data += 4; hit_size > 0; hit_size--, data++) { ldns_buffer_printf(output, "%02x", (int) *data); } ldns_buffer_write_u8(output, (uint8_t) ' '); if (ldns_buffer_reserve(output, ldns_b64_ntop_calculate_size(pk_size))) { written = ldns_b64_ntop(data, pk_size, (char *) ldns_buffer_current(output), ldns_buffer_remaining(output)); if (written > 0 && written < (int) ldns_buffer_remaining(output)) { output->_position += written; } } return ldns_buffer_status(output); } static ldns_status ldns_rdf2buffer_str_fmt(ldns_buffer *buffer, const ldns_output_format* fmt, const ldns_rdf *rdf) { ldns_status res = LDNS_STATUS_OK; /*ldns_buffer_printf(buffer, "%u:", ldns_rdf_get_type(rdf));*/ if (rdf) { switch(ldns_rdf_get_type(rdf)) { case LDNS_RDF_TYPE_NONE: break; case LDNS_RDF_TYPE_DNAME: res = ldns_rdf2buffer_str_dname(buffer, rdf); break; case LDNS_RDF_TYPE_INT8: /* Don't output mnemonics for these */ case LDNS_RDF_TYPE_ALG: case LDNS_RDF_TYPE_CERTIFICATE_USAGE: case LDNS_RDF_TYPE_SELECTOR: case LDNS_RDF_TYPE_MATCHING_TYPE: res = ldns_rdf2buffer_str_int8(buffer, rdf); break; case LDNS_RDF_TYPE_INT16: res = ldns_rdf2buffer_str_int16(buffer, rdf); break; case LDNS_RDF_TYPE_INT32: res = ldns_rdf2buffer_str_int32(buffer, rdf); break; case LDNS_RDF_TYPE_PERIOD: res = ldns_rdf2buffer_str_period(buffer, rdf); break; case LDNS_RDF_TYPE_TSIGTIME: res = ldns_rdf2buffer_str_tsigtime(buffer, rdf); break; case LDNS_RDF_TYPE_A: res = ldns_rdf2buffer_str_a(buffer, rdf); break; case LDNS_RDF_TYPE_AAAA: res = ldns_rdf2buffer_str_aaaa(buffer, rdf); break; case LDNS_RDF_TYPE_STR: res = ldns_rdf2buffer_str_str(buffer, rdf); break; case LDNS_RDF_TYPE_APL: res = ldns_rdf2buffer_str_apl(buffer, rdf); break; case LDNS_RDF_TYPE_B32_EXT: res = ldns_rdf2buffer_str_b32_ext(buffer, rdf); break; case LDNS_RDF_TYPE_B64: res = ldns_rdf2buffer_str_b64(buffer, rdf); break; case LDNS_RDF_TYPE_HEX: res = ldns_rdf2buffer_str_hex(buffer, rdf); break; case LDNS_RDF_TYPE_NSEC: res = ldns_rdf2buffer_str_nsec_fmt(buffer, fmt, rdf); break; case LDNS_RDF_TYPE_NSEC3_SALT: res = ldns_rdf2buffer_str_nsec3_salt(buffer, rdf); break; case LDNS_RDF_TYPE_TYPE: res = ldns_rdf2buffer_str_type_fmt(buffer, fmt, rdf); break; case LDNS_RDF_TYPE_CLASS: res = ldns_rdf2buffer_str_class(buffer, rdf); break; case LDNS_RDF_TYPE_CERT_ALG: res = ldns_rdf2buffer_str_cert_alg(buffer, rdf); break; case LDNS_RDF_TYPE_UNKNOWN: res = ldns_rdf2buffer_str_unknown(buffer, rdf); break; case LDNS_RDF_TYPE_TIME: res = ldns_rdf2buffer_str_time(buffer, rdf); break; case LDNS_RDF_TYPE_HIP: res = ldns_rdf2buffer_str_hip(buffer, rdf); break; case LDNS_RDF_TYPE_LOC: res = ldns_rdf2buffer_str_loc(buffer, rdf); break; case LDNS_RDF_TYPE_WKS: case LDNS_RDF_TYPE_SERVICE: res = ldns_rdf2buffer_str_wks(buffer, rdf); break; case LDNS_RDF_TYPE_NSAP: res = ldns_rdf2buffer_str_nsap(buffer, rdf); break; case LDNS_RDF_TYPE_ATMA: res = ldns_rdf2buffer_str_atma(buffer, rdf); break; case LDNS_RDF_TYPE_IPSECKEY: res = ldns_rdf2buffer_str_ipseckey(buffer, rdf); break; case LDNS_RDF_TYPE_INT16_DATA: res = ldns_rdf2buffer_str_int16_data(buffer, rdf); break; case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: res = ldns_rdf2buffer_str_b32_ext(buffer, rdf); break; case LDNS_RDF_TYPE_ILNP64: res = ldns_rdf2buffer_str_ilnp64(buffer, rdf); break; case LDNS_RDF_TYPE_EUI48: res = ldns_rdf2buffer_str_eui48(buffer, rdf); break; case LDNS_RDF_TYPE_EUI64: res = ldns_rdf2buffer_str_eui64(buffer, rdf); break; case LDNS_RDF_TYPE_TAG: res = ldns_rdf2buffer_str_tag(buffer, rdf); break; case LDNS_RDF_TYPE_LONG_STR: res = ldns_rdf2buffer_str_long_str(buffer, rdf); break; } } else { /** This will write mangled RRs */ ldns_buffer_printf(buffer, "(null) "); res = LDNS_STATUS_ERR; } return res; } ldns_status ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) { return ldns_rdf2buffer_str_fmt(buffer,ldns_output_format_default,rdf); } static ldns_rdf * ldns_b32_ext2dname(const ldns_rdf *rdf) { size_t size; char *b32; ldns_rdf *out; if(ldns_rdf_size(rdf) == 0) return NULL; /* remove -1 for the b32-hash-len octet */ size = ldns_b32_ntop_calculate_size(ldns_rdf_size(rdf) - 1); /* add one for the end nul for the string */ b32 = LDNS_XMALLOC(char, size + 2); if (b32) { if (ldns_b32_ntop_extended_hex(ldns_rdf_data(rdf) + 1, ldns_rdf_size(rdf) - 1, b32, size+1) > 0) { b32[size] = '.'; b32[size+1] = '\0'; if (ldns_str2rdf_dname(&out, b32) == LDNS_STATUS_OK) { LDNS_FREE(b32); return out; } } LDNS_FREE(b32); } return NULL; } static ldns_status ldns_rr2buffer_str_rfc3597(ldns_buffer *output, const ldns_rr *rr) { size_t total_rdfsize = 0; size_t i, j; ldns_buffer_printf(output, "TYPE%u\t", ldns_rr_get_type(rr)); for (i = 0; i < ldns_rr_rd_count(rr); i++) { total_rdfsize += ldns_rdf_size(ldns_rr_rdf(rr, i)); } if (total_rdfsize == 0) { ldns_buffer_printf(output, "\\# 0\n"); return ldns_buffer_status(output); } ldns_buffer_printf(output, "\\# %d ", total_rdfsize); for (i = 0; i < ldns_rr_rd_count(rr); i++) { for (j = 0; j < ldns_rdf_size(ldns_rr_rdf(rr, i)); j++) { ldns_buffer_printf(output, "%.2x", ldns_rdf_data(ldns_rr_rdf(rr, i))[j]); } } ldns_buffer_printf(output, "\n"); return ldns_buffer_status(output); } ldns_status ldns_rr2buffer_str_fmt(ldns_buffer *output, const ldns_output_format *fmt, const ldns_rr *rr) { uint16_t i, flags; ldns_status status = LDNS_STATUS_OK; ldns_output_format_storage* fmt_st = (ldns_output_format_storage*)fmt; if (fmt_st == NULL) { fmt_st = (ldns_output_format_storage*) ldns_output_format_default; } if (!rr) { if (LDNS_COMMENT_NULLS & fmt_st->flags) { ldns_buffer_printf(output, "; (null)\n"); } return ldns_buffer_status(output); } if (ldns_rr_owner(rr)) { status = ldns_rdf2buffer_str_dname(output, ldns_rr_owner(rr)); } if (status != LDNS_STATUS_OK) { return status; } /* TTL should NOT be printed if it is a question */ if (!ldns_rr_is_question(rr)) { ldns_buffer_printf(output, "\t%d", ldns_rr_ttl(rr)); } ldns_buffer_printf(output, "\t"); status = ldns_rr_class2buffer_str(output, ldns_rr_get_class(rr)); if (status != LDNS_STATUS_OK) { return status; } ldns_buffer_printf(output, "\t"); if (ldns_output_format_covers_type(fmt, ldns_rr_get_type(rr))) { return ldns_rr2buffer_str_rfc3597(output, rr); } status = ldns_rr_type2buffer_str(output, ldns_rr_get_type(rr)); if (status != LDNS_STATUS_OK) { return status; } if (ldns_rr_rd_count(rr) > 0) { ldns_buffer_printf(output, "\t"); } else if (!ldns_rr_is_question(rr)) { ldns_buffer_printf(output, "\t\\# 0"); } for (i = 0; i < ldns_rr_rd_count(rr); i++) { /* ldns_rdf2buffer_str handles NULL input fine! */ if ((fmt_st->flags & LDNS_FMT_ZEROIZE_RRSIGS) && (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) && ((/* inception */ i == 4 && ldns_rdf_get_type(ldns_rr_rdf(rr, 4)) == LDNS_RDF_TYPE_TIME) || (/* expiration */ i == 5 && ldns_rdf_get_type(ldns_rr_rdf(rr, 5)) == LDNS_RDF_TYPE_TIME) || (/* signature */ i == 8 && ldns_rdf_get_type(ldns_rr_rdf(rr, 8)) == LDNS_RDF_TYPE_B64))) { ldns_buffer_printf(output, "(null)"); status = ldns_buffer_status(output); } else if ((fmt_st->flags & LDNS_FMT_PAD_SOA_SERIAL) && (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) && /* serial */ i == 2 && ldns_rdf_get_type(ldns_rr_rdf(rr, 2)) == LDNS_RDF_TYPE_INT32) { ldns_buffer_printf(output, "%10lu", (unsigned long) ldns_read_uint32( ldns_rdf_data(ldns_rr_rdf(rr, 2)))); status = ldns_buffer_status(output); } else { status = ldns_rdf2buffer_str_fmt(output, fmt, ldns_rr_rdf(rr, i)); } if(status != LDNS_STATUS_OK) return status; if (i < ldns_rr_rd_count(rr) - 1) { ldns_buffer_printf(output, " "); } } /* per RR special comments - handy for DNSSEC types */ /* check to prevent question sec. rr from * getting here */ if (ldns_rr_rd_count(rr) > 0) { switch (ldns_rr_get_type(rr)) { case LDNS_RR_TYPE_DNSKEY: /* if ldns_rr_rd_count(rr) > 0 then ldns_rr_rdf(rr, 0) exists! */ if (! (fmt_st->flags & LDNS_COMMENT_KEY)) { break; } flags = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0)); ldns_buffer_printf(output, " ;{"); if (fmt_st->flags & LDNS_COMMENT_KEY_ID) { ldns_buffer_printf(output, "id = %u", (unsigned int) ldns_calc_keytag(rr)); } if ((fmt_st->flags & LDNS_COMMENT_KEY_TYPE) && (flags & LDNS_KEY_ZONE_KEY)){ if (flags & LDNS_KEY_SEP_KEY) { ldns_buffer_printf(output, " (ksk)"); } else { ldns_buffer_printf(output, " (zsk)"); } if (fmt_st->flags & LDNS_COMMENT_KEY_SIZE){ ldns_buffer_printf(output, ", "); } } else if (fmt_st->flags & (LDNS_COMMENT_KEY_ID |LDNS_COMMENT_KEY_SIZE)) { ldns_buffer_printf( output, ", "); } if (fmt_st->flags & LDNS_COMMENT_KEY_SIZE) { ldns_buffer_printf(output, "size = %db", ldns_rr_dnskey_key_size(rr)); } ldns_buffer_printf(output, "}"); break; case LDNS_RR_TYPE_RRSIG: if ((fmt_st->flags & LDNS_COMMENT_KEY) && (fmt_st->flags& LDNS_COMMENT_RRSIGS) && ldns_rr_rdf(rr, 6) != NULL) { ldns_buffer_printf(output, " ;{id = %d}", ldns_rdf2native_int16( ldns_rr_rdf(rr, 6))); } break; case LDNS_RR_TYPE_DS: if ((fmt_st->flags & LDNS_COMMENT_BUBBLEBABBLE) && ldns_rr_rdf(rr, 3) != NULL) { uint8_t *data = ldns_rdf_data( ldns_rr_rdf(rr, 3)); size_t len = ldns_rdf_size(ldns_rr_rdf(rr, 3)); char *babble = ldns_bubblebabble(data, len); if(babble) { ldns_buffer_printf(output, " ;{%s}", babble); } LDNS_FREE(babble); } break; case LDNS_RR_TYPE_NSEC3: if (! (fmt_st->flags & LDNS_COMMENT_FLAGS) && ! (fmt_st->flags & LDNS_COMMENT_NSEC3_CHAIN)) { break; } ldns_buffer_printf(output, " ;{"); if ((fmt_st->flags & LDNS_COMMENT_FLAGS)) { if (ldns_nsec3_optout(rr)) { ldns_buffer_printf(output, " flags: optout"); } else { ldns_buffer_printf(output," flags: -"); } if (fmt_st->flags & LDNS_COMMENT_NSEC3_CHAIN && fmt_st->hashmap != NULL) { ldns_buffer_printf(output, ", "); } } if (fmt_st->flags & LDNS_COMMENT_NSEC3_CHAIN && fmt_st->hashmap != NULL) { ldns_rbnode_t *node; ldns_rdf *key = ldns_dname_label( ldns_rr_owner(rr), 0); if (key) { node = ldns_rbtree_search( fmt_st->hashmap, (void *) key); if (node->data) { ldns_buffer_printf(output, "from: "); (void) ldns_rdf2buffer_str( output, ldns_dnssec_name_name( (ldns_dnssec_name*) node->data )); } ldns_rdf_free(key); } key = ldns_b32_ext2dname( ldns_nsec3_next_owner(rr)); if (key) { node = ldns_rbtree_search( fmt_st->hashmap, (void *) key); if (node->data) { ldns_buffer_printf(output, " to: "); (void) ldns_rdf2buffer_str( output, ldns_dnssec_name_name( (ldns_dnssec_name*) node->data )); } ldns_rdf_free(key); } } ldns_buffer_printf(output, "}"); break; default: break; } } /* last */ ldns_buffer_printf(output, "\n"); return ldns_buffer_status(output); } ldns_status ldns_rr2buffer_str(ldns_buffer *output, const ldns_rr *rr) { return ldns_rr2buffer_str_fmt(output, ldns_output_format_default, rr); } ldns_status ldns_rr_list2buffer_str_fmt(ldns_buffer *output, const ldns_output_format *fmt, const ldns_rr_list *list) { uint16_t i; for(i = 0; i < ldns_rr_list_rr_count(list); i++) { (void) ldns_rr2buffer_str_fmt(output, fmt, ldns_rr_list_rr(list, i)); } return ldns_buffer_status(output); } ldns_status ldns_rr_list2buffer_str(ldns_buffer *output, const ldns_rr_list *list) { return ldns_rr_list2buffer_str_fmt( output, ldns_output_format_default, list); } ldns_status ldns_pktheader2buffer_str(ldns_buffer *output, const ldns_pkt *pkt) { ldns_lookup_table *opcode = ldns_lookup_by_id(ldns_opcodes, (int) ldns_pkt_get_opcode(pkt)); ldns_lookup_table *rcode = ldns_lookup_by_id(ldns_rcodes, (int) ldns_pkt_get_rcode(pkt)); ldns_buffer_printf(output, ";; ->>HEADER<<- "); if (opcode) { ldns_buffer_printf(output, "opcode: %s, ", opcode->name); } else { ldns_buffer_printf(output, "opcode: ?? (%u), ", ldns_pkt_get_opcode(pkt)); } if (rcode) { ldns_buffer_printf(output, "rcode: %s, ", rcode->name); } else { ldns_buffer_printf(output, "rcode: ?? (%u), ", ldns_pkt_get_rcode(pkt)); } ldns_buffer_printf(output, "id: %d\n", ldns_pkt_id(pkt)); ldns_buffer_printf(output, ";; flags: "); if (ldns_pkt_qr(pkt)) { ldns_buffer_printf(output, "qr "); } if (ldns_pkt_aa(pkt)) { ldns_buffer_printf(output, "aa "); } if (ldns_pkt_tc(pkt)) { ldns_buffer_printf(output, "tc "); } if (ldns_pkt_rd(pkt)) { ldns_buffer_printf(output, "rd "); } if (ldns_pkt_cd(pkt)) { ldns_buffer_printf(output, "cd "); } if (ldns_pkt_ra(pkt)) { ldns_buffer_printf(output, "ra "); } if (ldns_pkt_ad(pkt)) { ldns_buffer_printf(output, "ad "); } ldns_buffer_printf(output, "; "); ldns_buffer_printf(output, "QUERY: %u, ", ldns_pkt_qdcount(pkt)); ldns_buffer_printf(output, "ANSWER: %u, ", ldns_pkt_ancount(pkt)); ldns_buffer_printf(output, "AUTHORITY: %u, ", ldns_pkt_nscount(pkt)); ldns_buffer_printf(output, "ADDITIONAL: %u ", ldns_pkt_arcount(pkt)); return ldns_buffer_status(output); } ldns_status ldns_pkt2buffer_str_fmt(ldns_buffer *output, const ldns_output_format *fmt, const ldns_pkt *pkt) { uint16_t i; ldns_status status = LDNS_STATUS_OK; char *tmp; struct timeval time; time_t time_tt; if (!pkt) { ldns_buffer_printf(output, "null"); return LDNS_STATUS_OK; } if (ldns_buffer_status_ok(output)) { status = ldns_pktheader2buffer_str(output, pkt); if (status != LDNS_STATUS_OK) { return status; } ldns_buffer_printf(output, "\n"); ldns_buffer_printf(output, ";; QUESTION SECTION:\n;; "); for (i = 0; i < ldns_pkt_qdcount(pkt); i++) { status = ldns_rr2buffer_str_fmt(output, fmt, ldns_rr_list_rr( ldns_pkt_question(pkt), i)); if (status != LDNS_STATUS_OK) { return status; } } ldns_buffer_printf(output, "\n"); ldns_buffer_printf(output, ";; ANSWER SECTION:\n"); for (i = 0; i < ldns_pkt_ancount(pkt); i++) { status = ldns_rr2buffer_str_fmt(output, fmt, ldns_rr_list_rr( ldns_pkt_answer(pkt), i)); if (status != LDNS_STATUS_OK) { return status; } } ldns_buffer_printf(output, "\n"); ldns_buffer_printf(output, ";; AUTHORITY SECTION:\n"); for (i = 0; i < ldns_pkt_nscount(pkt); i++) { status = ldns_rr2buffer_str_fmt(output, fmt, ldns_rr_list_rr( ldns_pkt_authority(pkt), i)); if (status != LDNS_STATUS_OK) { return status; } } ldns_buffer_printf(output, "\n"); ldns_buffer_printf(output, ";; ADDITIONAL SECTION:\n"); for (i = 0; i < ldns_pkt_arcount(pkt); i++) { status = ldns_rr2buffer_str_fmt(output, fmt, ldns_rr_list_rr( ldns_pkt_additional(pkt), i)); if (status != LDNS_STATUS_OK) { return status; } } ldns_buffer_printf(output, "\n"); /* add some futher fields */ ldns_buffer_printf(output, ";; Query time: %d msec\n", ldns_pkt_querytime(pkt)); if (ldns_pkt_edns(pkt)) { ldns_buffer_printf(output, ";; EDNS: version %u; flags:", ldns_pkt_edns_version(pkt)); if (ldns_pkt_edns_do(pkt)) { ldns_buffer_printf(output, " do"); } /* the extended rcode is the value set, shifted four bits, * and or'd with the original rcode */ if (ldns_pkt_edns_extended_rcode(pkt)) { ldns_buffer_printf(output, " ; ext-rcode: %d", (ldns_pkt_edns_extended_rcode(pkt) << 4 | ldns_pkt_get_rcode(pkt))); } ldns_buffer_printf(output, " ; udp: %u\n", ldns_pkt_edns_udp_size(pkt)); if (ldns_pkt_edns_data(pkt)) { ldns_buffer_printf(output, ";; Data: "); (void)ldns_rdf2buffer_str(output, ldns_pkt_edns_data(pkt)); ldns_buffer_printf(output, "\n"); } } if (ldns_pkt_tsig(pkt)) { ldns_buffer_printf(output, ";; TSIG:\n;; "); (void) ldns_rr2buffer_str_fmt( output, fmt, ldns_pkt_tsig(pkt)); ldns_buffer_printf(output, "\n"); } if (ldns_pkt_answerfrom(pkt)) { tmp = ldns_rdf2str(ldns_pkt_answerfrom(pkt)); ldns_buffer_printf(output, ";; SERVER: %s\n", tmp); LDNS_FREE(tmp); } time = ldns_pkt_timestamp(pkt); time_tt = (time_t)time.tv_sec; ldns_buffer_printf(output, ";; WHEN: %s", (char*)ctime(&time_tt)); ldns_buffer_printf(output, ";; MSG SIZE rcvd: %d\n", (int)ldns_pkt_size(pkt)); } else { return ldns_buffer_status(output); } return status; } ldns_status ldns_pkt2buffer_str(ldns_buffer *output, const ldns_pkt *pkt) { return ldns_pkt2buffer_str_fmt(output, ldns_output_format_default, pkt); } #ifdef HAVE_SSL static ldns_status ldns_hmac_key2buffer_str(ldns_buffer *output, const ldns_key *k) { ldns_status status; size_t i; ldns_rdf *b64_bignum; ldns_buffer_printf(output, "Key: "); i = ldns_key_hmac_size(k); b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, ldns_key_hmac_key(k)); status = ldns_rdf2buffer_str(output, b64_bignum); ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); return status; } #endif #if defined(HAVE_SSL) && defined(USE_GOST) static ldns_status ldns_gost_key2buffer_str(ldns_buffer *output, EVP_PKEY *p) { unsigned char* pp = NULL; int ret; ldns_rdf *b64_bignum; ldns_status status; ldns_buffer_printf(output, "GostAsn1: "); ret = i2d_PrivateKey(p, &pp); b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, (size_t)ret, pp); status = ldns_rdf2buffer_str(output, b64_bignum); ldns_rdf_deep_free(b64_bignum); OPENSSL_free(pp); ldns_buffer_printf(output, "\n"); return status; } #endif ldns_status ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k) { ldns_status status = LDNS_STATUS_OK; unsigned char *bignum; #ifdef HAVE_SSL # ifndef S_SPLINT_S uint16_t i; # endif /* not used when ssl is not defined */ /*@unused@*/ ldns_rdf *b64_bignum = NULL; RSA *rsa; DSA *dsa; #endif /* HAVE_SSL */ if (!k) { return LDNS_STATUS_ERR; } bignum = LDNS_XMALLOC(unsigned char, LDNS_MAX_KEYLEN); if (!bignum) { return LDNS_STATUS_ERR; } if (ldns_buffer_status_ok(output)) { #ifdef HAVE_SSL switch(ldns_key_algorithm(k)) { case LDNS_SIGN_RSASHA1: case LDNS_SIGN_RSASHA1_NSEC3: case LDNS_SIGN_RSASHA256: case LDNS_SIGN_RSASHA512: case LDNS_SIGN_RSAMD5: /* copied by looking at dnssec-keygen output */ /* header */ rsa = ldns_key_rsa_key(k); ldns_buffer_printf(output,"Private-key-format: v1.2\n"); switch(ldns_key_algorithm(k)) { case LDNS_SIGN_RSAMD5: ldns_buffer_printf(output, "Algorithm: %u (RSA)\n", LDNS_RSAMD5); break; case LDNS_SIGN_RSASHA1: ldns_buffer_printf(output, "Algorithm: %u (RSASHA1)\n", LDNS_RSASHA1); break; case LDNS_SIGN_RSASHA1_NSEC3: ldns_buffer_printf(output, "Algorithm: %u (RSASHA1_NSEC3)\n", LDNS_RSASHA1_NSEC3); break; #ifdef USE_SHA2 case LDNS_SIGN_RSASHA256: ldns_buffer_printf(output, "Algorithm: %u (RSASHA256)\n", LDNS_RSASHA256); break; case LDNS_SIGN_RSASHA512: ldns_buffer_printf(output, "Algorithm: %u (RSASHA512)\n", LDNS_RSASHA512); break; #endif default: #ifdef STDERR_MSGS fprintf(stderr, "Warning: unknown signature "); fprintf(stderr, "algorithm type %u\n", ldns_key_algorithm(k)); #endif ldns_buffer_printf(output, "Algorithm: %u (Unknown)\n", ldns_key_algorithm(k)); break; } /* print to buf, convert to bin, convert to b64, * print to buf */ ldns_buffer_printf(output, "Modulus: "); #ifndef S_SPLINT_S i = (uint16_t)BN_bn2bin(rsa->n, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); ldns_buffer_printf(output, "PublicExponent: "); i = (uint16_t)BN_bn2bin(rsa->e, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); ldns_buffer_printf(output, "PrivateExponent: "); if (rsa->d) { i = (uint16_t)BN_bn2bin(rsa->d, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { ldns_buffer_printf(output, "(Not available)\n"); } ldns_buffer_printf(output, "Prime1: "); if (rsa->p) { i = (uint16_t)BN_bn2bin(rsa->p, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { ldns_buffer_printf(output, "(Not available)\n"); } ldns_buffer_printf(output, "Prime2: "); if (rsa->q) { i = (uint16_t)BN_bn2bin(rsa->q, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { ldns_buffer_printf(output, "(Not available)\n"); } ldns_buffer_printf(output, "Exponent1: "); if (rsa->dmp1) { i = (uint16_t)BN_bn2bin(rsa->dmp1, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { ldns_buffer_printf(output, "(Not available)\n"); } ldns_buffer_printf(output, "Exponent2: "); if (rsa->dmq1) { i = (uint16_t)BN_bn2bin(rsa->dmq1, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { ldns_buffer_printf(output, "(Not available)\n"); } ldns_buffer_printf(output, "Coefficient: "); if (rsa->iqmp) { i = (uint16_t)BN_bn2bin(rsa->iqmp, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { ldns_buffer_printf(output, "(Not available)\n"); } #endif /* splint */ RSA_free(rsa); break; case LDNS_SIGN_DSA: case LDNS_SIGN_DSA_NSEC3: dsa = ldns_key_dsa_key(k); ldns_buffer_printf(output,"Private-key-format: v1.2\n"); if (ldns_key_algorithm(k) == LDNS_SIGN_DSA) { ldns_buffer_printf(output,"Algorithm: 3 (DSA)\n"); } else if (ldns_key_algorithm(k) == LDNS_SIGN_DSA_NSEC3) { ldns_buffer_printf(output,"Algorithm: 6 (DSA_NSEC3)\n"); } /* print to buf, convert to bin, convert to b64, * print to buf */ ldns_buffer_printf(output, "Prime(p): "); #ifndef S_SPLINT_S if (dsa->p) { i = (uint16_t)BN_bn2bin(dsa->p, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { printf("(Not available)\n"); } ldns_buffer_printf(output, "Subprime(q): "); if (dsa->q) { i = (uint16_t)BN_bn2bin(dsa->q, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { printf("(Not available)\n"); } ldns_buffer_printf(output, "Base(g): "); if (dsa->g) { i = (uint16_t)BN_bn2bin(dsa->g, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { printf("(Not available)\n"); } ldns_buffer_printf(output, "Private_value(x): "); if (dsa->priv_key) { i = (uint16_t)BN_bn2bin(dsa->priv_key, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { printf("(Not available)\n"); } ldns_buffer_printf(output, "Public_value(y): "); if (dsa->pub_key) { i = (uint16_t)BN_bn2bin(dsa->pub_key, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); } else { printf("(Not available)\n"); } #endif /* splint */ break; case LDNS_SIGN_ECC_GOST: /* no format defined, use blob */ #if defined(HAVE_SSL) && defined(USE_GOST) ldns_buffer_printf(output, "Private-key-format: v1.2\n"); ldns_buffer_printf(output, "Algorithm: %d (ECC-GOST)\n", LDNS_SIGN_ECC_GOST); status = ldns_gost_key2buffer_str(output, #ifndef S_SPLINT_S k->_key.key #else NULL #endif ); #else goto error; #endif /* GOST */ break; case LDNS_SIGN_ECDSAP256SHA256: case LDNS_SIGN_ECDSAP384SHA384: #ifdef USE_ECDSA ldns_buffer_printf(output, "Private-key-format: v1.2\n"); ldns_buffer_printf(output, "Algorithm: %d (", ldns_key_algorithm(k)); status=ldns_algorithm2buffer_str(output, (ldns_algorithm)ldns_key_algorithm(k)); #ifndef S_SPLINT_S ldns_buffer_printf(output, ")\n"); if(k->_key.key) { EC_KEY* ec = EVP_PKEY_get1_EC_KEY(k->_key.key); const BIGNUM* b = EC_KEY_get0_private_key(ec); ldns_buffer_printf(output, "PrivateKey: "); i = (uint16_t)BN_bn2bin(b, bignum); if (i > LDNS_MAX_KEYLEN) { goto error; } b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum); if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) { ldns_rdf_deep_free(b64_bignum); goto error; } ldns_rdf_deep_free(b64_bignum); ldns_buffer_printf(output, "\n"); /* down reference count in EC_KEY * its still assigned to the PKEY */ EC_KEY_free(ec); } #endif /* splint */ #else goto error; #endif /* ECDSA */ break; case LDNS_SIGN_HMACMD5: /* there's not much of a format defined for TSIG */ /* It's just a binary blob, Same for all algorithms */ ldns_buffer_printf(output, "Private-key-format: v1.2\n"); ldns_buffer_printf(output, "Algorithm: 157 (HMAC_MD5)\n"); status = ldns_hmac_key2buffer_str(output, k); break; case LDNS_SIGN_HMACSHA1: ldns_buffer_printf(output, "Private-key-format: v1.2\n"); ldns_buffer_printf(output, "Algorithm: 158 (HMAC_SHA1)\n"); status = ldns_hmac_key2buffer_str(output, k); break; case LDNS_SIGN_HMACSHA256: ldns_buffer_printf(output, "Private-key-format: v1.2\n"); ldns_buffer_printf(output, "Algorithm: 159 (HMAC_SHA256)\n"); status = ldns_hmac_key2buffer_str(output, k); break; } #endif /* HAVE_SSL */ } else { LDNS_FREE(bignum); return ldns_buffer_status(output); } LDNS_FREE(bignum); return status; #ifdef HAVE_SSL /* compiles warn the label isn't used */ error: LDNS_FREE(bignum); return LDNS_STATUS_ERR; #endif /* HAVE_SSL */ } /* * Zero terminate the buffer and copy data. */ char * ldns_buffer2str(ldns_buffer *buffer) { char *str; /* check if buffer ends with \0, if not, and if there is space, add it */ if (*(ldns_buffer_at(buffer, ldns_buffer_position(buffer))) != 0) { if (!ldns_buffer_reserve(buffer, 1)) { return NULL; } ldns_buffer_write_u8(buffer, (uint8_t) '\0'); if (!ldns_buffer_set_capacity(buffer, ldns_buffer_position(buffer))) { return NULL; } } str = strdup((const char *)ldns_buffer_begin(buffer)); if(!str) { return NULL; } return str; } /* * Zero terminate the buffer and export data. */ char * ldns_buffer_export2str(ldns_buffer *buffer) { /* Append '\0' as string terminator */ if (! ldns_buffer_reserve(buffer, 1)) { return NULL; } ldns_buffer_write_u8(buffer, 0); /* reallocate memory to the size of the string and export */ ldns_buffer_set_capacity(buffer, ldns_buffer_position(buffer)); return ldns_buffer_export(buffer); } char * ldns_rdf2str(const ldns_rdf *rdf) { char *result = NULL; ldns_buffer *tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!tmp_buffer) { return NULL; } if (ldns_rdf2buffer_str(tmp_buffer, rdf) == LDNS_STATUS_OK) { /* export and return string, destroy rest */ result = ldns_buffer_export2str(tmp_buffer); } ldns_buffer_free(tmp_buffer); return result; } char * ldns_rr2str_fmt(const ldns_output_format *fmt, const ldns_rr *rr) { char *result = NULL; ldns_buffer *tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!tmp_buffer) { return NULL; } if (ldns_rr2buffer_str_fmt(tmp_buffer, fmt, rr) == LDNS_STATUS_OK) { /* export and return string, destroy rest */ result = ldns_buffer_export2str(tmp_buffer); } ldns_buffer_free(tmp_buffer); return result; } char * ldns_rr2str(const ldns_rr *rr) { return ldns_rr2str_fmt(ldns_output_format_default, rr); } char * ldns_pkt2str_fmt(const ldns_output_format *fmt, const ldns_pkt *pkt) { char *result = NULL; ldns_buffer *tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!tmp_buffer) { return NULL; } if (ldns_pkt2buffer_str_fmt(tmp_buffer, fmt, pkt) == LDNS_STATUS_OK) { /* export and return string, destroy rest */ result = ldns_buffer_export2str(tmp_buffer); } ldns_buffer_free(tmp_buffer); return result; } char * ldns_pkt2str(const ldns_pkt *pkt) { return ldns_pkt2str_fmt(ldns_output_format_default, pkt); } char * ldns_key2str(const ldns_key *k) { char *result = NULL; ldns_buffer *tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!tmp_buffer) { return NULL; } if (ldns_key2buffer_str(tmp_buffer, k) == LDNS_STATUS_OK) { /* export and return string, destroy rest */ result = ldns_buffer_export2str(tmp_buffer); } ldns_buffer_free(tmp_buffer); return result; } char * ldns_rr_list2str_fmt(const ldns_output_format *fmt, const ldns_rr_list *list) { char *result = NULL; ldns_buffer *tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!tmp_buffer) { return NULL; } if (list) { if (ldns_rr_list2buffer_str_fmt( tmp_buffer, fmt, list) == LDNS_STATUS_OK) { } } else { if (fmt == NULL) { fmt = ldns_output_format_default; } if (fmt->flags & LDNS_COMMENT_NULLS) { ldns_buffer_printf(tmp_buffer, "; (null)\n"); } } /* export and return string, destroy rest */ result = ldns_buffer_export2str(tmp_buffer); ldns_buffer_free(tmp_buffer); return result; } char * ldns_rr_list2str(const ldns_rr_list *list) { return ldns_rr_list2str_fmt(ldns_output_format_default, list); } void ldns_rdf_print(FILE *output, const ldns_rdf *rdf) { char *str = ldns_rdf2str(rdf); if (str) { fprintf(output, "%s", str); } else { fprintf(output, ";Unable to convert rdf to string\n"); } LDNS_FREE(str); } void ldns_rr_print_fmt(FILE *output, const ldns_output_format *fmt, const ldns_rr *rr) { char *str = ldns_rr2str_fmt(fmt, rr); if (str) { fprintf(output, "%s", str); } else { fprintf(output, ";Unable to convert rr to string\n"); } LDNS_FREE(str); } void ldns_rr_print(FILE *output, const ldns_rr *rr) { ldns_rr_print_fmt(output, ldns_output_format_default, rr); } void ldns_pkt_print_fmt(FILE *output, const ldns_output_format *fmt, const ldns_pkt *pkt) { char *str = ldns_pkt2str_fmt(fmt, pkt); if (str) { fprintf(output, "%s", str); } else { fprintf(output, ";Unable to convert packet to string\n"); } LDNS_FREE(str); } void ldns_pkt_print(FILE *output, const ldns_pkt *pkt) { ldns_pkt_print_fmt(output, ldns_output_format_default, pkt); } void ldns_rr_list_print_fmt(FILE *output, const ldns_output_format *fmt, const ldns_rr_list *lst) { size_t i; for (i = 0; i < ldns_rr_list_rr_count(lst); i++) { ldns_rr_print_fmt(output, fmt, ldns_rr_list_rr(lst, i)); } } void ldns_rr_list_print(FILE *output, const ldns_rr_list *lst) { ldns_rr_list_print_fmt(output, ldns_output_format_default, lst); } void ldns_resolver_print_fmt(FILE *output, const ldns_output_format *fmt, const ldns_resolver *r) { uint16_t i; ldns_rdf **n; ldns_rdf **s; size_t *rtt; if (!r) { return; } n = ldns_resolver_nameservers(r); s = ldns_resolver_searchlist(r); rtt = ldns_resolver_rtt(r); fprintf(output, "port: %d\n", (int)ldns_resolver_port(r)); fprintf(output, "edns0 size: %d\n", (int)ldns_resolver_edns_udp_size(r)); fprintf(output, "use ip6: %d\n", (int)ldns_resolver_ip6(r)); fprintf(output, "recursive: %d\n", ldns_resolver_recursive(r)); fprintf(output, "usevc: %d\n", ldns_resolver_usevc(r)); fprintf(output, "igntc: %d\n", ldns_resolver_igntc(r)); fprintf(output, "fail: %d\n", ldns_resolver_fail(r)); fprintf(output, "retry: %d\n", (int)ldns_resolver_retry(r)); fprintf(output, "retrans: %d\n", (int)ldns_resolver_retrans(r)); fprintf(output, "fallback: %d\n", ldns_resolver_fallback(r)); fprintf(output, "random: %d\n", ldns_resolver_random(r)); fprintf(output, "timeout: %d\n", (int)ldns_resolver_timeout(r).tv_sec); fprintf(output, "dnssec: %d\n", ldns_resolver_dnssec(r)); fprintf(output, "dnssec cd: %d\n", ldns_resolver_dnssec_cd(r)); fprintf(output, "trust anchors (%d listed):\n", (int)ldns_rr_list_rr_count(ldns_resolver_dnssec_anchors(r))); ldns_rr_list_print_fmt(output, fmt, ldns_resolver_dnssec_anchors(r)); fprintf(output, "tsig: %s %s\n", ldns_resolver_tsig_keyname(r)?ldns_resolver_tsig_keyname(r):"-", ldns_resolver_tsig_algorithm(r)?ldns_resolver_tsig_algorithm(r):"-"); fprintf(output, "debug: %d\n", ldns_resolver_debug(r)); fprintf(output, "default domain: "); ldns_rdf_print(output, ldns_resolver_domain(r)); fprintf(output, "\n"); fprintf(output, "apply default domain: %d\n", ldns_resolver_defnames(r)); fprintf(output, "searchlist (%d listed):\n", (int)ldns_resolver_searchlist_count(r)); for (i = 0; i < ldns_resolver_searchlist_count(r); i++) { fprintf(output, "\t"); ldns_rdf_print(output, s[i]); fprintf(output, "\n"); } fprintf(output, "apply search list: %d\n", ldns_resolver_dnsrch(r)); fprintf(output, "nameservers (%d listed):\n", (int)ldns_resolver_nameserver_count(r)); for (i = 0; i < ldns_resolver_nameserver_count(r); i++) { fprintf(output, "\t"); ldns_rdf_print(output, n[i]); switch ((int)rtt[i]) { case LDNS_RESOLV_RTT_MIN: fprintf(output, " - reachable\n"); break; case LDNS_RESOLV_RTT_INF: fprintf(output, " - unreachable\n"); break; } } } void ldns_resolver_print(FILE *output, const ldns_resolver *r) { ldns_resolver_print_fmt(output, ldns_output_format_default, r); } void ldns_zone_print_fmt(FILE *output, const ldns_output_format *fmt, const ldns_zone *z) { if(ldns_zone_soa(z)) ldns_rr_print_fmt(output, fmt, ldns_zone_soa(z)); ldns_rr_list_print_fmt(output, fmt, ldns_zone_rrs(z)); } void ldns_zone_print(FILE *output, const ldns_zone *z) { ldns_zone_print_fmt(output, ldns_output_format_default, z); } Net-LDNS-0.75/src/ldns/host2wire.c000644 000770 000024 00000032225 12471046240 017141 0ustar00calledstaff000000 000000 /* * host2wire.c * * conversion routines from the host to the wire format. * This will usually just a re-ordering of the * data (as we store it in network format) * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include ldns_status ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name) { return ldns_dname2buffer_wire_compress(buffer, name, NULL); } ldns_status ldns_dname2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *name, ldns_rbtree_t *compression_data) { ldns_rbnode_t *node; uint8_t *data; size_t size; ldns_rdf *label; ldns_rdf *rest; ldns_status s; /* If no tree, just add the data */ if(!compression_data) { if (ldns_buffer_reserve(buffer, ldns_rdf_size(name))) { ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name)); } return ldns_buffer_status(buffer); } /* No labels left, write final zero */ if(ldns_dname_label_count(name)==0) { if(ldns_buffer_reserve(buffer,1)) { ldns_buffer_write_u8(buffer, 0); } return ldns_buffer_status(buffer); } /* Can we find the name in the tree? */ if((node = ldns_rbtree_search(compression_data, ldns_rdf_data(name))) != NULL) { /* Found */ uint16_t position = (uint16_t) (intptr_t) node->data | 0xC000; if (ldns_buffer_reserve(buffer, 2)) { ldns_buffer_write_u16(buffer, position); } return ldns_buffer_status(buffer); } else { /* Not found. Write cache entry, take off first label, write it, */ /* try again with the rest of the name. */ ldns_rbnode_t *node = LDNS_MALLOC(ldns_rbnode_t); if(!node) { return LDNS_STATUS_MEM_ERR; } if (ldns_buffer_position(buffer) < 16384) { node->key = strdup((const char *)ldns_rdf_data(name)); node->data = (void *) (intptr_t) ldns_buffer_position(buffer); if(!ldns_rbtree_insert(compression_data,node)) { /* fprintf(stderr,"Name not found but now it's there?\n"); */ } } label = ldns_dname_label(name, 0); rest = ldns_dname_left_chop(name); size = ldns_rdf_size(label) - 1; /* Don't want the final zero */ data = ldns_rdf_data(label); if(ldns_buffer_reserve(buffer, size)) { ldns_buffer_write(buffer, data, size); } ldns_rdf_deep_free(label); s = ldns_dname2buffer_wire_compress(buffer, rest, compression_data); ldns_rdf_deep_free(rest); return s; } } ldns_status ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf) { return ldns_rdf2buffer_wire_compress(buffer, rdf, NULL); } ldns_status ldns_rdf2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *rdf, ldns_rbtree_t *compression_data) { /* If it's a DNAME, call that function to get compression */ if(compression_data && ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) { return ldns_dname2buffer_wire_compress(buffer,rdf,compression_data); } if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) { ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf)); } return ldns_buffer_status(buffer); } ldns_status ldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf) { size_t i; uint8_t *rdf_data; if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) { if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) { rdf_data = ldns_rdf_data(rdf); for (i = 0; i < ldns_rdf_size(rdf); i++) { ldns_buffer_write_u8(buffer, (uint8_t) LDNS_DNAME_NORMALIZE((int)rdf_data[i])); } } } else { /* direct copy for all other types */ if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) { ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf)); } } return ldns_buffer_status(buffer); } /* convert a rr list to wireformat */ ldns_status ldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list) { uint16_t rr_count; uint16_t i; rr_count = ldns_rr_list_rr_count(rr_list); for(i = 0; i < rr_count; i++) { (void)ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANY); } return ldns_buffer_status(buffer); } ldns_status ldns_rr2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rr *rr, int section) { uint16_t i; uint16_t rdl_pos = 0; bool pre_rfc3597 = false; switch (ldns_rr_get_type(rr)) { case LDNS_RR_TYPE_NS: case LDNS_RR_TYPE_MD: case LDNS_RR_TYPE_MF: case LDNS_RR_TYPE_CNAME: case LDNS_RR_TYPE_SOA: case LDNS_RR_TYPE_MB: case LDNS_RR_TYPE_MG: case LDNS_RR_TYPE_MR: case LDNS_RR_TYPE_PTR: case LDNS_RR_TYPE_HINFO: case LDNS_RR_TYPE_MINFO: case LDNS_RR_TYPE_MX: case LDNS_RR_TYPE_RP: case LDNS_RR_TYPE_AFSDB: case LDNS_RR_TYPE_RT: case LDNS_RR_TYPE_SIG: case LDNS_RR_TYPE_PX: case LDNS_RR_TYPE_NXT: case LDNS_RR_TYPE_NAPTR: case LDNS_RR_TYPE_KX: case LDNS_RR_TYPE_SRV: case LDNS_RR_TYPE_DNAME: case LDNS_RR_TYPE_A6: case LDNS_RR_TYPE_RRSIG: pre_rfc3597 = true; break; default: break; } if (ldns_rr_owner(rr)) { (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr)); } if (ldns_buffer_reserve(buffer, 4)) { (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr)); (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr)); } if (section != LDNS_SECTION_QUESTION) { if (ldns_buffer_reserve(buffer, 6)) { ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr)); /* remember pos for later */ rdl_pos = ldns_buffer_position(buffer); ldns_buffer_write_u16(buffer, 0); } for (i = 0; i < ldns_rr_rd_count(rr); i++) { if (pre_rfc3597) { (void) ldns_rdf2buffer_wire_canonical( buffer, ldns_rr_rdf(rr, i)); } else { (void) ldns_rdf2buffer_wire( buffer, ldns_rr_rdf(rr, i)); } } if (rdl_pos != 0) { ldns_buffer_write_u16_at(buffer, rdl_pos, ldns_buffer_position(buffer) - rdl_pos - 2); } } return ldns_buffer_status(buffer); } ldns_status ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section) { return ldns_rr2buffer_wire_compress(buffer,rr,section,NULL); } ldns_status ldns_rr2buffer_wire_compress(ldns_buffer *buffer, const ldns_rr *rr, int section, ldns_rbtree_t *compression_data) { uint16_t i; uint16_t rdl_pos = 0; if (ldns_rr_owner(rr)) { (void) ldns_dname2buffer_wire_compress(buffer, ldns_rr_owner(rr), compression_data); } if (ldns_buffer_reserve(buffer, 4)) { (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr)); (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr)); } if (section != LDNS_SECTION_QUESTION) { if (ldns_buffer_reserve(buffer, 6)) { ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr)); /* remember pos for later */ rdl_pos = ldns_buffer_position(buffer); ldns_buffer_write_u16(buffer, 0); } if (LDNS_RR_COMPRESS == ldns_rr_descript(ldns_rr_get_type(rr))->_compress) { for (i = 0; i < ldns_rr_rd_count(rr); i++) { (void) ldns_rdf2buffer_wire_compress(buffer, ldns_rr_rdf(rr, i), compression_data); } } else { for (i = 0; i < ldns_rr_rd_count(rr); i++) { (void) ldns_rdf2buffer_wire( buffer, ldns_rr_rdf(rr, i)); } } if (rdl_pos != 0) { ldns_buffer_write_u16_at(buffer, rdl_pos, ldns_buffer_position(buffer) - rdl_pos - 2); } } return ldns_buffer_status(buffer); } ldns_status ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr) { uint16_t i; /* it must be a sig RR */ if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) { return LDNS_STATUS_ERR; } /* Convert all the rdfs, except the actual signature data * rdf number 8 - the last, hence: -1 */ for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) { (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_rdf(rr, i)); } return ldns_buffer_status(buffer); } ldns_status ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr) { uint16_t i; /* convert all the rdf's */ for (i = 0; i < ldns_rr_rd_count(rr); i++) { (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr,i)); } return ldns_buffer_status(buffer); } /* * Copies the packet header data to the buffer in wire format */ static ldns_status ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) { uint8_t flags; uint16_t arcount; if (ldns_buffer_reserve(buffer, 12)) { ldns_buffer_write_u16(buffer, ldns_pkt_id(packet)); flags = ldns_pkt_qr(packet) << 7 | ldns_pkt_get_opcode(packet) << 3 | ldns_pkt_aa(packet) << 2 | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet); ldns_buffer_write_u8(buffer, flags); flags = ldns_pkt_ra(packet) << 7 /*| ldns_pkt_z(packet) << 6*/ | ldns_pkt_ad(packet) << 5 | ldns_pkt_cd(packet) << 4 | ldns_pkt_get_rcode(packet); ldns_buffer_write_u8(buffer, flags); ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet)); ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet)); ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet)); /* add EDNS0 and TSIG to additional if they are there */ arcount = ldns_pkt_arcount(packet); if (ldns_pkt_tsig(packet)) { arcount++; } if (ldns_pkt_edns(packet)) { arcount++; } ldns_buffer_write_u16(buffer, arcount); } return ldns_buffer_status(buffer); } void compression_node_free(ldns_rbnode_t *node, void *arg) { (void)arg; /* Yes, dear compiler, it is used */ free((void *)node->key); LDNS_FREE(node); } ldns_status ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) { ldns_rr_list *rr_list; uint16_t i; /* edns tmp vars */ ldns_rr *edns_rr; uint8_t edata[4]; ldns_rbtree_t *compression_data = ldns_rbtree_create((int (*)(const void *, const void *))strcasecmp); (void) ldns_hdr2buffer_wire(buffer, packet); rr_list = ldns_pkt_question(packet); if (rr_list) { for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { (void) ldns_rr2buffer_wire_compress(buffer, ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION, compression_data); } } rr_list = ldns_pkt_answer(packet); if (rr_list) { for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { (void) ldns_rr2buffer_wire_compress(buffer, ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER, compression_data); } } rr_list = ldns_pkt_authority(packet); if (rr_list) { for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { (void) ldns_rr2buffer_wire_compress(buffer, ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY, compression_data); } } rr_list = ldns_pkt_additional(packet); if (rr_list) { for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { (void) ldns_rr2buffer_wire_compress(buffer, ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL, compression_data); } } /* add EDNS to additional if it is needed */ if (ldns_pkt_edns(packet)) { edns_rr = ldns_rr_new(); if(!edns_rr) return LDNS_STATUS_MEM_ERR; ldns_rr_set_owner(edns_rr, ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, ".")); ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT); ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet)); edata[0] = ldns_pkt_edns_extended_rcode(packet); edata[1] = ldns_pkt_edns_version(packet); ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet)); ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata)); /* don't forget to add the edns rdata (if any) */ if (packet->_edns_data) ldns_rr_push_rdf (edns_rr, packet->_edns_data); (void)ldns_rr2buffer_wire_compress(buffer, edns_rr, LDNS_SECTION_ADDITIONAL, compression_data); /* take the edns rdata back out of the rr before we free rr */ if (packet->_edns_data) (void)ldns_rr_pop_rdf (edns_rr); ldns_rr_free(edns_rr); } /* add TSIG to additional if it is there */ if (ldns_pkt_tsig(packet)) { (void) ldns_rr2buffer_wire_compress(buffer, ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL, compression_data); } ldns_traverse_postorder(compression_data,compression_node_free,NULL); ldns_rbtree_free(compression_data); return LDNS_STATUS_OK; } ldns_status ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size) { ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); ldns_status status; *result_size = 0; *dest = NULL; if(!buffer) return LDNS_STATUS_MEM_ERR; status = ldns_rdf2buffer_wire(buffer, rdf); if (status == LDNS_STATUS_OK) { *result_size = ldns_buffer_position(buffer); *dest = (uint8_t *) ldns_buffer_export(buffer); } ldns_buffer_free(buffer); return status; } ldns_status ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size) { ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); ldns_status status; *result_size = 0; *dest = NULL; if(!buffer) return LDNS_STATUS_MEM_ERR; status = ldns_rr2buffer_wire(buffer, rr, section); if (status == LDNS_STATUS_OK) { *result_size = ldns_buffer_position(buffer); *dest = (uint8_t *) ldns_buffer_export(buffer); } ldns_buffer_free(buffer); return status; } ldns_status ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size) { ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); ldns_status status; *result_size = 0; *dest = NULL; if(!buffer) return LDNS_STATUS_MEM_ERR; status = ldns_pkt2buffer_wire(buffer, packet); if (status == LDNS_STATUS_OK) { *result_size = ldns_buffer_position(buffer); *dest = (uint8_t *) ldns_buffer_export(buffer); } ldns_buffer_free(buffer); return status; } Net-LDNS-0.75/src/ldns/keys.c000644 000770 000024 00000120216 12471046240 016164 0ustar00calledstaff000000 000000 /* * keys.c handle private keys for use in DNSSEC * * This module should hide some of the openSSL complexities * and give a general interface for private keys and hmac * handling * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include #ifdef HAVE_SSL #include #include #include #endif /* HAVE_SSL */ ldns_lookup_table ldns_signing_algorithms[] = { { LDNS_SIGN_RSAMD5, "RSAMD5" }, { LDNS_SIGN_RSASHA1, "RSASHA1" }, { LDNS_SIGN_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" }, #ifdef USE_SHA2 { LDNS_SIGN_RSASHA256, "RSASHA256" }, { LDNS_SIGN_RSASHA512, "RSASHA512" }, #endif #ifdef USE_GOST { LDNS_SIGN_ECC_GOST, "ECC-GOST" }, #endif #ifdef USE_ECDSA { LDNS_SIGN_ECDSAP256SHA256, "ECDSAP256SHA256" }, { LDNS_SIGN_ECDSAP384SHA384, "ECDSAP384SHA384" }, #endif { LDNS_SIGN_DSA, "DSA" }, { LDNS_SIGN_DSA_NSEC3, "DSA-NSEC3-SHA1" }, { LDNS_SIGN_HMACMD5, "hmac-md5.sig-alg.reg.int" }, { LDNS_SIGN_HMACSHA1, "hmac-sha1" }, { LDNS_SIGN_HMACSHA256, "hmac-sha256" }, { 0, NULL } }; ldns_key_list * ldns_key_list_new(void) { ldns_key_list *key_list = LDNS_MALLOC(ldns_key_list); if (!key_list) { return NULL; } else { key_list->_key_count = 0; key_list->_keys = NULL; return key_list; } } ldns_key * ldns_key_new(void) { ldns_key *newkey; newkey = LDNS_MALLOC(ldns_key); if (!newkey) { return NULL; } else { /* some defaults - not sure wether to do this */ ldns_key_set_use(newkey, true); ldns_key_set_flags(newkey, LDNS_KEY_ZONE_KEY); ldns_key_set_origttl(newkey, 0); ldns_key_set_keytag(newkey, 0); ldns_key_set_inception(newkey, 0); ldns_key_set_expiration(newkey, 0); ldns_key_set_pubkey_owner(newkey, NULL); #ifdef HAVE_SSL ldns_key_set_evp_key(newkey, NULL); #endif /* HAVE_SSL */ ldns_key_set_hmac_key(newkey, NULL); ldns_key_set_external_key(newkey, NULL); return newkey; } } ldns_status ldns_key_new_frm_fp(ldns_key **k, FILE *fp) { return ldns_key_new_frm_fp_l(k, fp, NULL); } #ifdef HAVE_SSL ldns_status ldns_key_new_frm_engine(ldns_key **key, ENGINE *e, char *key_id, ldns_algorithm alg) { ldns_key *k; k = ldns_key_new(); if(!k) return LDNS_STATUS_MEM_ERR; #ifndef S_SPLINT_S k->_key.key = ENGINE_load_private_key(e, key_id, UI_OpenSSL(), NULL); if(!k->_key.key) { ldns_key_free(k); return LDNS_STATUS_ERR; } ldns_key_set_algorithm(k, (ldns_signing_algorithm) alg); if (!k->_key.key) { ldns_key_free(k); return LDNS_STATUS_ENGINE_KEY_NOT_LOADED; } #endif /* splint */ *key = k; return LDNS_STATUS_OK; } #endif #ifdef USE_GOST /** store GOST engine reference loaded into OpenSSL library */ ENGINE* ldns_gost_engine = NULL; int ldns_key_EVP_load_gost_id(void) { static int gost_id = 0; const EVP_PKEY_ASN1_METHOD* meth; ENGINE* e; if(gost_id) return gost_id; /* see if configuration loaded gost implementation from other engine*/ meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1); if(meth) { EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); return gost_id; } /* see if engine can be loaded already */ e = ENGINE_by_id("gost"); if(!e) { /* load it ourself, in case statically linked */ ENGINE_load_builtin_engines(); ENGINE_load_dynamic(); e = ENGINE_by_id("gost"); } if(!e) { /* no gost engine in openssl */ return 0; } if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { ENGINE_finish(e); ENGINE_free(e); return 0; } meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1); if(!meth) { /* algo not found */ ENGINE_finish(e); ENGINE_free(e); return 0; } /* Note: do not ENGINE_finish and ENGINE_free the acquired engine * on some platforms this frees up the meth and unloads gost stuff */ ldns_gost_engine = e; EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); return gost_id; } void ldns_key_EVP_unload_gost(void) { if(ldns_gost_engine) { ENGINE_finish(ldns_gost_engine); ENGINE_free(ldns_gost_engine); ldns_gost_engine = NULL; } } /** read GOST private key */ static EVP_PKEY* ldns_key_new_frm_fp_gost_l(FILE* fp, int* line_nr) { char token[16384]; const unsigned char* pp; int gost_id; EVP_PKEY* pkey; ldns_rdf* b64rdf = NULL; gost_id = ldns_key_EVP_load_gost_id(); if(!gost_id) return NULL; if (ldns_fget_keyword_data_l(fp, "GostAsn1", ": ", token, "\n", sizeof(token), line_nr) == -1) return NULL; while(strlen(token) < 96) { /* read more b64 from the file, b64 split on multiple lines */ if(ldns_fget_token_l(fp, token+strlen(token), "\n", sizeof(token)-strlen(token), line_nr) == -1) return NULL; } if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK) return NULL; pp = (unsigned char*)ldns_rdf_data(b64rdf); pkey = d2i_PrivateKey(gost_id, NULL, &pp, (int)ldns_rdf_size(b64rdf)); ldns_rdf_deep_free(b64rdf); return pkey; } #endif #ifdef USE_ECDSA /** calculate public key from private key */ static int ldns_EC_KEY_calc_public(EC_KEY* ec) { EC_POINT* pub_key; const EC_GROUP* group; group = EC_KEY_get0_group(ec); pub_key = EC_POINT_new(group); if(!pub_key) return 0; if(!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))) { EC_POINT_free(pub_key); return 0; } if(!EC_POINT_mul(group, pub_key, EC_KEY_get0_private_key(ec), NULL, NULL, NULL)) { EC_POINT_free(pub_key); return 0; } if(EC_KEY_set_public_key(ec, pub_key) == 0) { EC_POINT_free(pub_key); return 0; } EC_POINT_free(pub_key); return 1; } /** read ECDSA private key */ static EVP_PKEY* ldns_key_new_frm_fp_ecdsa_l(FILE* fp, ldns_algorithm alg, int* line_nr) { char token[16384]; ldns_rdf* b64rdf = NULL; unsigned char* pp; BIGNUM* bn; EVP_PKEY* evp_key; EC_KEY* ec; if (ldns_fget_keyword_data_l(fp, "PrivateKey", ": ", token, "\n", sizeof(token), line_nr) == -1) return NULL; if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK) return NULL; pp = (unsigned char*)ldns_rdf_data(b64rdf); if(alg == LDNS_ECDSAP256SHA256) ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); else if(alg == LDNS_ECDSAP384SHA384) ec = EC_KEY_new_by_curve_name(NID_secp384r1); else ec = NULL; if(!ec) { ldns_rdf_deep_free(b64rdf); return NULL; } bn = BN_bin2bn(pp, (int)ldns_rdf_size(b64rdf), NULL); ldns_rdf_deep_free(b64rdf); if(!bn) { EC_KEY_free(ec); return NULL; } EC_KEY_set_private_key(ec, bn); BN_free(bn); if(!ldns_EC_KEY_calc_public(ec)) { EC_KEY_free(ec); return NULL; } evp_key = EVP_PKEY_new(); if(!evp_key) { EC_KEY_free(ec); return NULL; } if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) { EVP_PKEY_free(evp_key); EC_KEY_free(ec); return NULL; } return evp_key; } #endif ldns_status ldns_key_new_frm_fp_l(ldns_key **key, FILE *fp, int *line_nr) { ldns_key *k; char *d; ldns_signing_algorithm alg; ldns_rr *key_rr; #ifdef HAVE_SSL RSA *rsa; DSA *dsa; unsigned char *hmac; size_t hmac_size; #endif /* HAVE_SSL */ k = ldns_key_new(); d = LDNS_XMALLOC(char, LDNS_MAX_LINELEN); if (!k || !d) { ldns_key_free(k); LDNS_FREE(d); return LDNS_STATUS_MEM_ERR; } alg = 0; /* the file is highly structured. Do this in sequence */ /* RSA: * Private-key-format: v1.x. * Algorithm: 1 (RSA) */ /* get the key format version number */ if (ldns_fget_keyword_data_l(fp, "Private-key-format", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { /* no version information */ ldns_key_free(k); LDNS_FREE(d); return LDNS_STATUS_SYNTAX_ERR; } if (strncmp(d, "v1.", 3) != 0) { ldns_key_free(k); LDNS_FREE(d); return LDNS_STATUS_SYNTAX_VERSION_ERR; } /* get the algorithm type, our file function strip ( ) so there are * not in the return string! */ if (ldns_fget_keyword_data_l(fp, "Algorithm", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { /* no alg information */ ldns_key_free(k); LDNS_FREE(d); return LDNS_STATUS_SYNTAX_ALG_ERR; } if (strncmp(d, "1 RSA", 2) == 0) { alg = LDNS_SIGN_RSAMD5; } if (strncmp(d, "2 DH", 2) == 0) { alg = (ldns_signing_algorithm)LDNS_DH; } if (strncmp(d, "3 DSA", 2) == 0) { alg = LDNS_SIGN_DSA; } if (strncmp(d, "4 ECC", 2) == 0) { alg = (ldns_signing_algorithm)LDNS_ECC; } if (strncmp(d, "5 RSASHA1", 2) == 0) { alg = LDNS_SIGN_RSASHA1; } if (strncmp(d, "6 DSA", 2) == 0) { alg = LDNS_SIGN_DSA_NSEC3; } if (strncmp(d, "7 RSASHA1", 2) == 0) { alg = LDNS_SIGN_RSASHA1_NSEC3; } if (strncmp(d, "8 RSASHA256", 2) == 0) { #ifdef USE_SHA2 alg = LDNS_SIGN_RSASHA256; #else # ifdef STDERR_MSGS fprintf(stderr, "Warning: SHA256 not compiled into this "); fprintf(stderr, "version of ldns\n"); # endif #endif } if (strncmp(d, "10 RSASHA512", 3) == 0) { #ifdef USE_SHA2 alg = LDNS_SIGN_RSASHA512; #else # ifdef STDERR_MSGS fprintf(stderr, "Warning: SHA512 not compiled into this "); fprintf(stderr, "version of ldns\n"); # endif #endif } if (strncmp(d, "12 ECC-GOST", 3) == 0) { #ifdef USE_GOST alg = LDNS_SIGN_ECC_GOST; #else # ifdef STDERR_MSGS fprintf(stderr, "Warning: ECC-GOST not compiled into this "); fprintf(stderr, "version of ldns, use --enable-gost\n"); # endif #endif } if (strncmp(d, "13 ECDSAP256SHA256", 3) == 0) { #ifdef USE_ECDSA alg = LDNS_SIGN_ECDSAP256SHA256; #else # ifdef STDERR_MSGS fprintf(stderr, "Warning: ECDSA not compiled into this "); fprintf(stderr, "version of ldns, use --enable-ecdsa\n"); # endif #endif } if (strncmp(d, "14 ECDSAP384SHA384", 3) == 0) { #ifdef USE_ECDSA alg = LDNS_SIGN_ECDSAP384SHA384; #else # ifdef STDERR_MSGS fprintf(stderr, "Warning: ECDSA not compiled into this "); fprintf(stderr, "version of ldns, use --enable-ecdsa\n"); # endif #endif } if (strncmp(d, "157 HMAC-MD5", 4) == 0) { alg = LDNS_SIGN_HMACMD5; } if (strncmp(d, "158 HMAC-SHA1", 4) == 0) { alg = LDNS_SIGN_HMACSHA1; } if (strncmp(d, "159 HMAC-SHA256", 4) == 0) { alg = LDNS_SIGN_HMACSHA256; } LDNS_FREE(d); switch(alg) { case LDNS_SIGN_RSAMD5: case LDNS_SIGN_RSASHA1: case LDNS_SIGN_RSASHA1_NSEC3: #ifdef USE_SHA2 case LDNS_SIGN_RSASHA256: case LDNS_SIGN_RSASHA512: #endif ldns_key_set_algorithm(k, alg); #ifdef HAVE_SSL rsa = ldns_key_new_frm_fp_rsa_l(fp, line_nr); if (!rsa) { ldns_key_free(k); return LDNS_STATUS_ERR; } ldns_key_assign_rsa_key(k, rsa); #endif /* HAVE_SSL */ break; case LDNS_SIGN_DSA: case LDNS_SIGN_DSA_NSEC3: ldns_key_set_algorithm(k, alg); #ifdef HAVE_SSL dsa = ldns_key_new_frm_fp_dsa_l(fp, line_nr); if (!dsa) { ldns_key_free(k); return LDNS_STATUS_ERR; } ldns_key_assign_dsa_key(k, dsa); #endif /* HAVE_SSL */ break; case LDNS_SIGN_HMACMD5: case LDNS_SIGN_HMACSHA1: case LDNS_SIGN_HMACSHA256: ldns_key_set_algorithm(k, alg); #ifdef HAVE_SSL hmac = ldns_key_new_frm_fp_hmac_l(fp, line_nr, &hmac_size); if (!hmac) { ldns_key_free(k); return LDNS_STATUS_ERR; } ldns_key_set_hmac_size(k, hmac_size); ldns_key_set_hmac_key(k, hmac); #endif /* HAVE_SSL */ break; case LDNS_SIGN_ECC_GOST: ldns_key_set_algorithm(k, alg); #if defined(HAVE_SSL) && defined(USE_GOST) if(!ldns_key_EVP_load_gost_id()) { ldns_key_free(k); return LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL; } ldns_key_set_evp_key(k, ldns_key_new_frm_fp_gost_l(fp, line_nr)); #ifndef S_SPLINT_S if(!k->_key.key) { ldns_key_free(k); return LDNS_STATUS_ERR; } #endif /* splint */ #endif break; #ifdef USE_ECDSA case LDNS_SIGN_ECDSAP256SHA256: case LDNS_SIGN_ECDSAP384SHA384: ldns_key_set_algorithm(k, alg); ldns_key_set_evp_key(k, ldns_key_new_frm_fp_ecdsa_l(fp, (ldns_algorithm)alg, line_nr)); #ifndef S_SPLINT_S if(!k->_key.key) { ldns_key_free(k); return LDNS_STATUS_ERR; } #endif /* splint */ break; #endif default: ldns_key_free(k); return LDNS_STATUS_SYNTAX_ALG_ERR; } key_rr = ldns_key2rr(k); ldns_key_set_keytag(k, ldns_calc_keytag(key_rr)); ldns_rr_free(key_rr); if (key) { *key = k; return LDNS_STATUS_OK; } ldns_key_free(k); return LDNS_STATUS_ERR; } #ifdef HAVE_SSL RSA * ldns_key_new_frm_fp_rsa(FILE *f) { return ldns_key_new_frm_fp_rsa_l(f, NULL); } RSA * ldns_key_new_frm_fp_rsa_l(FILE *f, int *line_nr) { /* we parse * Modulus: * PublicExponent: * PrivateExponent: * Prime1: * Prime2: * Exponent1: * Exponent2: * Coefficient: * * man 3 RSA: * * struct * { * BIGNUM *n; // public modulus * BIGNUM *e; // public exponent * BIGNUM *d; // private exponent * BIGNUM *p; // secret prime factor * BIGNUM *q; // secret prime factor * BIGNUM *dmp1; // d mod (p-1) * BIGNUM *dmq1; // d mod (q-1) * BIGNUM *iqmp; // q^-1 mod p * // ... * */ char *d; RSA *rsa; uint8_t *buf; int i; d = LDNS_XMALLOC(char, LDNS_MAX_LINELEN); buf = LDNS_XMALLOC(uint8_t, LDNS_MAX_LINELEN); rsa = RSA_new(); if (!d || !rsa || !buf) { goto error; } /* I could use functions again, but that seems an overkill, * allthough this also looks tedious */ /* Modules, rsa->n */ if (ldns_fget_keyword_data_l(f, "Modulus", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); #ifndef S_SPLINT_S rsa->n = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!rsa->n) { goto error; } /* PublicExponent, rsa->e */ if (ldns_fget_keyword_data_l(f, "PublicExponent", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); rsa->e = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!rsa->e) { goto error; } /* PrivateExponent, rsa->d */ if (ldns_fget_keyword_data_l(f, "PrivateExponent", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); rsa->d = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!rsa->d) { goto error; } /* Prime1, rsa->p */ if (ldns_fget_keyword_data_l(f, "Prime1", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); rsa->p = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!rsa->p) { goto error; } /* Prime2, rsa->q */ if (ldns_fget_keyword_data_l(f, "Prime2", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); rsa->q = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!rsa->q) { goto error; } /* Exponent1, rsa->dmp1 */ if (ldns_fget_keyword_data_l(f, "Exponent1", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); rsa->dmp1 = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!rsa->dmp1) { goto error; } /* Exponent2, rsa->dmq1 */ if (ldns_fget_keyword_data_l(f, "Exponent2", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); rsa->dmq1 = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!rsa->dmq1) { goto error; } /* Coefficient, rsa->iqmp */ if (ldns_fget_keyword_data_l(f, "Coefficient", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); rsa->iqmp = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!rsa->iqmp) { goto error; } #endif /* splint */ LDNS_FREE(buf); LDNS_FREE(d); return rsa; error: RSA_free(rsa); LDNS_FREE(d); LDNS_FREE(buf); return NULL; } DSA * ldns_key_new_frm_fp_dsa(FILE *f) { return ldns_key_new_frm_fp_dsa_l(f, NULL); } DSA * ldns_key_new_frm_fp_dsa_l(FILE *f, ATTR_UNUSED(int *line_nr)) { int i; char *d; DSA *dsa; uint8_t *buf; d = LDNS_XMALLOC(char, LDNS_MAX_LINELEN); buf = LDNS_XMALLOC(uint8_t, LDNS_MAX_LINELEN); dsa = DSA_new(); if (!d || !dsa || !buf) { goto error; } /* the line parser removes the () from the input... */ /* Prime, dsa->p */ if (ldns_fget_keyword_data_l(f, "Primep", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); #ifndef S_SPLINT_S dsa->p = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!dsa->p) { goto error; } /* Subprime, dsa->q */ if (ldns_fget_keyword_data_l(f, "Subprimeq", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); dsa->q = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!dsa->q) { goto error; } /* Base, dsa->g */ if (ldns_fget_keyword_data_l(f, "Baseg", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); dsa->g = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!dsa->g) { goto error; } /* Private key, dsa->priv_key */ if (ldns_fget_keyword_data_l(f, "Private_valuex", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); dsa->priv_key = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!dsa->priv_key) { goto error; } /* Public key, dsa->priv_key */ if (ldns_fget_keyword_data_l(f, "Public_valuey", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d))); dsa->pub_key = BN_bin2bn((const char unsigned*)buf, i, NULL); if (!dsa->pub_key) { goto error; } #endif /* splint */ LDNS_FREE(buf); LDNS_FREE(d); return dsa; error: LDNS_FREE(d); LDNS_FREE(buf); DSA_free(dsa); return NULL; } unsigned char * ldns_key_new_frm_fp_hmac(FILE *f, size_t *hmac_size) { return ldns_key_new_frm_fp_hmac_l(f, NULL, hmac_size); } unsigned char * ldns_key_new_frm_fp_hmac_l( FILE *f , ATTR_UNUSED(int *line_nr) , size_t *hmac_size ) { size_t i, bufsz; char d[LDNS_MAX_LINELEN]; unsigned char *buf = NULL; if (ldns_fget_keyword_data_l(f, "Key", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) { goto error; } bufsz = ldns_b64_ntop_calculate_size(strlen(d)); buf = LDNS_XMALLOC(unsigned char, bufsz); i = (size_t) ldns_b64_pton((const char*)d, buf, bufsz); *hmac_size = i; return buf; error: LDNS_FREE(buf); *hmac_size = 0; return NULL; } #endif /* HAVE_SSL */ #ifdef USE_GOST static EVP_PKEY* ldns_gen_gost_key(void) { EVP_PKEY_CTX* ctx; EVP_PKEY* p = NULL; int gost_id = ldns_key_EVP_load_gost_id(); if(!gost_id) return NULL; ctx = EVP_PKEY_CTX_new_id(gost_id, NULL); if(!ctx) { /* the id should be available now */ return NULL; } if(EVP_PKEY_CTX_ctrl_str(ctx, "paramset", "A") <= 0) { /* cannot set paramset */ EVP_PKEY_CTX_free(ctx); return NULL; } if(EVP_PKEY_keygen_init(ctx) <= 0) { EVP_PKEY_CTX_free(ctx); return NULL; } if(EVP_PKEY_keygen(ctx, &p) <= 0) { EVP_PKEY_free(p); EVP_PKEY_CTX_free(ctx); return NULL; } EVP_PKEY_CTX_free(ctx); return p; } #endif ldns_key * ldns_key_new_frm_algorithm(ldns_signing_algorithm alg, uint16_t size) { ldns_key *k; #ifdef HAVE_SSL DSA *d; RSA *r; # ifdef USE_ECDSA EC_KEY *ec = NULL; # endif #else int i; uint16_t offset = 0; #endif unsigned char *hmac; k = ldns_key_new(); if (!k) { return NULL; } switch(alg) { case LDNS_SIGN_RSAMD5: case LDNS_SIGN_RSASHA1: case LDNS_SIGN_RSASHA1_NSEC3: case LDNS_SIGN_RSASHA256: case LDNS_SIGN_RSASHA512: #ifdef HAVE_SSL r = RSA_generate_key((int)size, RSA_F4, NULL, NULL); if(!r) { ldns_key_free(k); return NULL; } if (RSA_check_key(r) != 1) { ldns_key_free(k); return NULL; } ldns_key_set_rsa_key(k, r); RSA_free(r); #endif /* HAVE_SSL */ break; case LDNS_SIGN_DSA: case LDNS_SIGN_DSA_NSEC3: #ifdef HAVE_SSL d = DSA_generate_parameters((int)size, NULL, 0, NULL, NULL, NULL, NULL); if (!d) { ldns_key_free(k); return NULL; } if (DSA_generate_key(d) != 1) { ldns_key_free(k); return NULL; } ldns_key_set_dsa_key(k, d); DSA_free(d); #endif /* HAVE_SSL */ break; case LDNS_SIGN_HMACMD5: case LDNS_SIGN_HMACSHA1: case LDNS_SIGN_HMACSHA256: #ifdef HAVE_SSL #ifndef S_SPLINT_S k->_key.key = NULL; #endif /* splint */ #endif /* HAVE_SSL */ size = size / 8; ldns_key_set_hmac_size(k, size); hmac = LDNS_XMALLOC(unsigned char, size); if(!hmac) { ldns_key_free(k); return NULL; } #ifdef HAVE_SSL if (RAND_bytes(hmac, (int) size) != 1) { LDNS_FREE(hmac); ldns_key_free(k); return NULL; } #else while (offset + sizeof(i) < size) { i = random(); memcpy(&hmac[offset], &i, sizeof(i)); offset += sizeof(i); } if (offset < size) { i = random(); memcpy(&hmac[offset], &i, size - offset); } #endif /* HAVE_SSL */ ldns_key_set_hmac_key(k, hmac); ldns_key_set_flags(k, 0); break; case LDNS_SIGN_ECC_GOST: #if defined(HAVE_SSL) && defined(USE_GOST) ldns_key_set_evp_key(k, ldns_gen_gost_key()); #ifndef S_SPLINT_S if(!k->_key.key) { ldns_key_free(k); return NULL; } #endif /* splint */ #else ldns_key_free(k); return NULL; #endif /* HAVE_SSL and USE_GOST */ break; case LDNS_SIGN_ECDSAP256SHA256: case LDNS_SIGN_ECDSAP384SHA384: #ifdef USE_ECDSA if(alg == LDNS_SIGN_ECDSAP256SHA256) ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); else if(alg == LDNS_SIGN_ECDSAP384SHA384) ec = EC_KEY_new_by_curve_name(NID_secp384r1); if(!ec) { ldns_key_free(k); return NULL; } if(!EC_KEY_generate_key(ec)) { ldns_key_free(k); EC_KEY_free(ec); return NULL; } #ifndef S_SPLINT_S k->_key.key = EVP_PKEY_new(); if(!k->_key.key) { ldns_key_free(k); EC_KEY_free(ec); return NULL; } if (!EVP_PKEY_assign_EC_KEY(k->_key.key, ec)) { ldns_key_free(k); EC_KEY_free(ec); return NULL; } #endif /* splint */ #else ldns_key_free(k); return NULL; #endif /* ECDSA */ break; } ldns_key_set_algorithm(k, alg); return k; } void ldns_key_print(FILE *output, const ldns_key *k) { char *str = ldns_key2str(k); if (str) { fprintf(output, "%s", str); } else { fprintf(output, "Unable to convert private key to string\n"); } LDNS_FREE(str); } void ldns_key_set_algorithm(ldns_key *k, ldns_signing_algorithm l) { k->_alg = l; } void ldns_key_set_flags(ldns_key *k, uint16_t f) { k->_extra.dnssec.flags = f; } #ifdef HAVE_SSL #ifndef S_SPLINT_S void ldns_key_set_evp_key(ldns_key *k, EVP_PKEY *e) { k->_key.key = e; } void ldns_key_set_rsa_key(ldns_key *k, RSA *r) { EVP_PKEY *key = EVP_PKEY_new(); EVP_PKEY_set1_RSA(key, r); k->_key.key = key; } void ldns_key_set_dsa_key(ldns_key *k, DSA *d) { EVP_PKEY *key = EVP_PKEY_new(); EVP_PKEY_set1_DSA(key, d); k->_key.key = key; } void ldns_key_assign_rsa_key(ldns_key *k, RSA *r) { EVP_PKEY *key = EVP_PKEY_new(); EVP_PKEY_assign_RSA(key, r); k->_key.key = key; } void ldns_key_assign_dsa_key(ldns_key *k, DSA *d) { EVP_PKEY *key = EVP_PKEY_new(); EVP_PKEY_assign_DSA(key, d); k->_key.key = key; } #endif /* splint */ #endif /* HAVE_SSL */ void ldns_key_set_hmac_key(ldns_key *k, unsigned char *hmac) { k->_key.hmac.key = hmac; } void ldns_key_set_hmac_size(ldns_key *k, size_t hmac_size) { k->_key.hmac.size = hmac_size; } void ldns_key_set_external_key(ldns_key *k, void *external_key) { k->_key.external_key = external_key; } void ldns_key_set_origttl(ldns_key *k, uint32_t t) { k->_extra.dnssec.orig_ttl = t; } void ldns_key_set_inception(ldns_key *k, uint32_t i) { k->_extra.dnssec.inception = i; } void ldns_key_set_expiration(ldns_key *k, uint32_t e) { k->_extra.dnssec.expiration = e; } void ldns_key_set_pubkey_owner(ldns_key *k, ldns_rdf *r) { k->_pubkey_owner = r; } void ldns_key_set_keytag(ldns_key *k, uint16_t tag) { k->_extra.dnssec.keytag = tag; } /* read */ size_t ldns_key_list_key_count(const ldns_key_list *key_list) { return key_list->_key_count; } ldns_key * ldns_key_list_key(const ldns_key_list *key, size_t nr) { if (nr < ldns_key_list_key_count(key)) { return key->_keys[nr]; } else { return NULL; } } ldns_signing_algorithm ldns_key_algorithm(const ldns_key *k) { return k->_alg; } void ldns_key_set_use(ldns_key *k, bool v) { if (k) { k->_use = v; } } bool ldns_key_use(const ldns_key *k) { if (k) { return k->_use; } return false; } #ifdef HAVE_SSL #ifndef S_SPLINT_S EVP_PKEY * ldns_key_evp_key(const ldns_key *k) { return k->_key.key; } RSA * ldns_key_rsa_key(const ldns_key *k) { if (k->_key.key) { return EVP_PKEY_get1_RSA(k->_key.key); } else { return NULL; } } DSA * ldns_key_dsa_key(const ldns_key *k) { if (k->_key.key) { return EVP_PKEY_get1_DSA(k->_key.key); } else { return NULL; } } #endif /* splint */ #endif /* HAVE_SSL */ unsigned char * ldns_key_hmac_key(const ldns_key *k) { if (k->_key.hmac.key) { return k->_key.hmac.key; } else { return NULL; } } size_t ldns_key_hmac_size(const ldns_key *k) { if (k->_key.hmac.size) { return k->_key.hmac.size; } else { return 0; } } void * ldns_key_external_key(const ldns_key *k) { return k->_key.external_key; } uint32_t ldns_key_origttl(const ldns_key *k) { return k->_extra.dnssec.orig_ttl; } uint16_t ldns_key_flags(const ldns_key *k) { return k->_extra.dnssec.flags; } uint32_t ldns_key_inception(const ldns_key *k) { return k->_extra.dnssec.inception; } uint32_t ldns_key_expiration(const ldns_key *k) { return k->_extra.dnssec.expiration; } uint16_t ldns_key_keytag(const ldns_key *k) { return k->_extra.dnssec.keytag; } ldns_rdf * ldns_key_pubkey_owner(const ldns_key *k) { return k->_pubkey_owner; } /* write */ void ldns_key_list_set_use(ldns_key_list *keys, bool v) { size_t i; for (i = 0; i < ldns_key_list_key_count(keys); i++) { ldns_key_set_use(ldns_key_list_key(keys, i), v); } } void ldns_key_list_set_key_count(ldns_key_list *key, size_t count) { key->_key_count = count; } bool ldns_key_list_push_key(ldns_key_list *key_list, ldns_key *key) { size_t key_count; ldns_key **keys; key_count = ldns_key_list_key_count(key_list); /* grow the array */ keys = LDNS_XREALLOC( key_list->_keys, ldns_key *, key_count + 1); if (!keys) { return false; } /* add the new member */ key_list->_keys = keys; key_list->_keys[key_count] = key; ldns_key_list_set_key_count(key_list, key_count + 1); return true; } ldns_key * ldns_key_list_pop_key(ldns_key_list *key_list) { size_t key_count; ldns_key** a; ldns_key *pop; if (!key_list) { return NULL; } key_count = ldns_key_list_key_count(key_list); if (key_count == 0) { return NULL; } pop = ldns_key_list_key(key_list, key_count); /* shrink the array */ a = LDNS_XREALLOC(key_list->_keys, ldns_key *, key_count - 1); if(a) { key_list->_keys = a; } ldns_key_list_set_key_count(key_list, key_count - 1); return pop; } #ifdef HAVE_SSL #ifndef S_SPLINT_S /* data pointer must be large enough (LDNS_MAX_KEYLEN) */ static bool ldns_key_rsa2bin(unsigned char *data, RSA *k, uint16_t *size) { int i,j; if (!k) { return false; } if (BN_num_bytes(k->e) <= 256) { /* normally only this path is executed (small factors are * more common */ data[0] = (unsigned char) BN_num_bytes(k->e); i = BN_bn2bin(k->e, data + 1); j = BN_bn2bin(k->n, data + i + 1); *size = (uint16_t) i + j; } else if (BN_num_bytes(k->e) <= 65536) { data[0] = 0; /* BN_bn2bin does bigendian, _uint16 also */ ldns_write_uint16(data + 1, (uint16_t) BN_num_bytes(k->e)); BN_bn2bin(k->e, data + 3); BN_bn2bin(k->n, data + 4 + BN_num_bytes(k->e)); *size = (uint16_t) BN_num_bytes(k->n) + 6; } else { return false; } return true; } /* data pointer must be large enough (LDNS_MAX_KEYLEN) */ static bool ldns_key_dsa2bin(unsigned char *data, DSA *k, uint16_t *size) { uint8_t T; if (!k) { return false; } /* See RFC2536 */ *size = (uint16_t)BN_num_bytes(k->p); T = (*size - 64) / 8; if (T > 8) { #ifdef STDERR_MSGS fprintf(stderr, "DSA key with T > 8 (ie. > 1024 bits)"); fprintf(stderr, " not implemented\n"); #endif return false; } /* size = 64 + (T * 8); */ memset(data, 0, 21 + *size * 3); data[0] = (unsigned char)T; BN_bn2bin(k->q, data + 1 ); /* 20 octects */ BN_bn2bin(k->p, data + 21 ); /* offset octects */ BN_bn2bin(k->g, data + 21 + *size * 2 - BN_num_bytes(k->g)); BN_bn2bin(k->pub_key,data + 21 + *size * 3 - BN_num_bytes(k->pub_key)); *size = 21 + *size * 3; return true; } #ifdef USE_GOST static bool ldns_key_gost2bin(unsigned char* data, EVP_PKEY* k, uint16_t* size) { int i; unsigned char* pp = NULL; if(i2d_PUBKEY(k, &pp) != 37 + 64) { /* expect 37 byte(ASN header) and 64 byte(X and Y) */ CRYPTO_free(pp); return false; } /* omit ASN header */ for(i=0; i<64; i++) data[i] = pp[i+37]; CRYPTO_free(pp); *size = 64; return true; } #endif /* USE_GOST */ #endif /* splint */ #endif /* HAVE_SSL */ ldns_rr * ldns_key2rr(const ldns_key *k) { /* this function will convert a the keydata contained in * rsa/dsa pointers to a DNSKEY rr. It will fill in as * much as it can, but it does not know about key-flags * for instance */ ldns_rr *pubkey; ldns_rdf *keybin; unsigned char *bin = NULL; uint16_t size = 0; #ifdef HAVE_SSL RSA *rsa = NULL; DSA *dsa = NULL; #endif /* HAVE_SSL */ #ifdef USE_ECDSA EC_KEY* ec; #endif int internal_data = 0; if (!k) { return NULL; } pubkey = ldns_rr_new(); switch (ldns_key_algorithm(k)) { case LDNS_SIGN_HMACMD5: case LDNS_SIGN_HMACSHA1: case LDNS_SIGN_HMACSHA256: ldns_rr_set_type(pubkey, LDNS_RR_TYPE_KEY); break; default: ldns_rr_set_type(pubkey, LDNS_RR_TYPE_DNSKEY); break; } /* zero-th rdf - flags */ ldns_rr_push_rdf(pubkey, ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, ldns_key_flags(k))); /* first - proto */ ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, LDNS_DNSSEC_KEYPROTO)); if (ldns_key_pubkey_owner(k)) { ldns_rr_set_owner(pubkey, ldns_rdf_clone(ldns_key_pubkey_owner(k))); } /* third - da algorithm */ switch(ldns_key_algorithm(k)) { case LDNS_SIGN_RSAMD5: case LDNS_SIGN_RSASHA1: case LDNS_SIGN_RSASHA1_NSEC3: case LDNS_SIGN_RSASHA256: case LDNS_SIGN_RSASHA512: ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, ldns_key_algorithm(k))); #ifdef HAVE_SSL rsa = ldns_key_rsa_key(k); if (rsa) { bin = LDNS_XMALLOC(unsigned char, LDNS_MAX_KEYLEN); if (!bin) { ldns_rr_free(pubkey); return NULL; } if (!ldns_key_rsa2bin(bin, rsa, &size)) { LDNS_FREE(bin); ldns_rr_free(pubkey); return NULL; } RSA_free(rsa); internal_data = 1; } #endif size++; break; case LDNS_SIGN_DSA: ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, LDNS_DSA)); #ifdef HAVE_SSL dsa = ldns_key_dsa_key(k); if (dsa) { bin = LDNS_XMALLOC(unsigned char, LDNS_MAX_KEYLEN); if (!bin) { ldns_rr_free(pubkey); return NULL; } if (!ldns_key_dsa2bin(bin, dsa, &size)) { LDNS_FREE(bin); ldns_rr_free(pubkey); return NULL; } DSA_free(dsa); internal_data = 1; } #endif /* HAVE_SSL */ break; case LDNS_SIGN_DSA_NSEC3: ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, LDNS_DSA_NSEC3)); #ifdef HAVE_SSL dsa = ldns_key_dsa_key(k); if (dsa) { bin = LDNS_XMALLOC(unsigned char, LDNS_MAX_KEYLEN); if (!bin) { ldns_rr_free(pubkey); return NULL; } if (!ldns_key_dsa2bin(bin, dsa, &size)) { LDNS_FREE(bin); ldns_rr_free(pubkey); return NULL; } DSA_free(dsa); internal_data = 1; } #endif /* HAVE_SSL */ break; case LDNS_SIGN_ECC_GOST: ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8( LDNS_RDF_TYPE_ALG, ldns_key_algorithm(k))); #if defined(HAVE_SSL) && defined(USE_GOST) bin = LDNS_XMALLOC(unsigned char, LDNS_MAX_KEYLEN); if (!bin) { ldns_rr_free(pubkey); return NULL; } #ifndef S_SPLINT_S if (!ldns_key_gost2bin(bin, k->_key.key, &size)) { LDNS_FREE(bin); ldns_rr_free(pubkey); return NULL; } #endif /* splint */ internal_data = 1; #else ldns_rr_free(pubkey); return NULL; #endif /* HAVE_SSL and USE_GOST */ break; case LDNS_SIGN_ECDSAP256SHA256: case LDNS_SIGN_ECDSAP384SHA384: #ifdef USE_ECDSA ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8( LDNS_RDF_TYPE_ALG, ldns_key_algorithm(k))); bin = NULL; #ifndef S_SPLINT_S ec = EVP_PKEY_get1_EC_KEY(k->_key.key); #endif EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED); size = (uint16_t)i2o_ECPublicKey(ec, NULL); if(!i2o_ECPublicKey(ec, &bin)) { EC_KEY_free(ec); ldns_rr_free(pubkey); return NULL; } if(size > 1) { /* move back one byte to shave off the 0x02 * 'uncompressed' indicator that openssl made * Actually its 0x04 (from implementation). */ assert(bin[0] == POINT_CONVERSION_UNCOMPRESSED); size -= 1; memmove(bin, bin+1, size); } /* down the reference count for ec, its still assigned * to the pkey */ EC_KEY_free(ec); internal_data = 1; #else ldns_rr_free(pubkey); return NULL; #endif /* ECDSA */ break; case LDNS_SIGN_HMACMD5: case LDNS_SIGN_HMACSHA1: case LDNS_SIGN_HMACSHA256: bin = LDNS_XMALLOC(unsigned char, ldns_key_hmac_size(k)); if (!bin) { ldns_rr_free(pubkey); return NULL; } ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, ldns_key_algorithm(k))); size = ldns_key_hmac_size(k); memcpy(bin, ldns_key_hmac_key(k), size); internal_data = 1; break; } /* fourth the key bin material */ if (internal_data) { keybin = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, size, bin); LDNS_FREE(bin); ldns_rr_push_rdf(pubkey, keybin); } return pubkey; } void ldns_key_free(ldns_key *key) { LDNS_FREE(key); } void ldns_key_deep_free(ldns_key *key) { unsigned char* hmac; if (ldns_key_pubkey_owner(key)) { ldns_rdf_deep_free(ldns_key_pubkey_owner(key)); } #ifdef HAVE_SSL if (ldns_key_evp_key(key)) { EVP_PKEY_free(ldns_key_evp_key(key)); } #endif /* HAVE_SSL */ if (ldns_key_hmac_key(key)) { hmac = ldns_key_hmac_key(key); LDNS_FREE(hmac); } LDNS_FREE(key); } void ldns_key_list_free(ldns_key_list *key_list) { size_t i; for (i = 0; i < ldns_key_list_key_count(key_list); i++) { ldns_key_deep_free(ldns_key_list_key(key_list, i)); } LDNS_FREE(key_list->_keys); LDNS_FREE(key_list); } ldns_rr * ldns_read_anchor_file(const char *filename) { FILE *fp; /*char line[LDNS_MAX_PACKETLEN];*/ char *line = LDNS_XMALLOC(char, LDNS_MAX_PACKETLEN); int c; size_t i = 0; ldns_rr *r; ldns_status status; if(!line) { return NULL; } fp = fopen(filename, "r"); if (!fp) { #ifdef STDERR_MSGS fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno)); #endif LDNS_FREE(line); return NULL; } while ((c = fgetc(fp)) && i+1 < LDNS_MAX_PACKETLEN && c != EOF) { line[i] = c; i++; } line[i] = '\0'; fclose(fp); if (i <= 0) { #ifdef STDERR_MSGS fprintf(stderr, "nothing read from %s", filename); #endif LDNS_FREE(line); return NULL; } else { status = ldns_rr_new_frm_str(&r, line, 0, NULL, NULL); if (status == LDNS_STATUS_OK && (ldns_rr_get_type(r) == LDNS_RR_TYPE_DNSKEY || ldns_rr_get_type(r) == LDNS_RR_TYPE_DS)) { LDNS_FREE(line); return r; } else { #ifdef STDERR_MSGS fprintf(stderr, "Error creating DNSKEY or DS rr from %s: %s\n", filename, ldns_get_errorstr_by_id(status)); #endif LDNS_FREE(line); return NULL; } } } char * ldns_key_get_file_base_name(ldns_key *key) { ldns_buffer *buffer; char *file_base_name; buffer = ldns_buffer_new(255); ldns_buffer_printf(buffer, "K"); (void)ldns_rdf2buffer_str_dname(buffer, ldns_key_pubkey_owner(key)); ldns_buffer_printf(buffer, "+%03u+%05u", ldns_key_algorithm(key), ldns_key_keytag(key)); file_base_name = ldns_buffer_export(buffer); ldns_buffer_free(buffer); return file_base_name; } int ldns_key_algo_supported(int algo) { ldns_lookup_table *lt = ldns_signing_algorithms; while(lt->name) { if(lt->id == algo) return 1; lt++; } return 0; } ldns_signing_algorithm ldns_get_signing_algorithm_by_name(const char* name) { /* list of (signing algorithm id, alias_name) */ ldns_lookup_table aliases[] = { /* from bind dnssec-keygen */ {LDNS_SIGN_HMACMD5, "HMAC-MD5"}, {LDNS_SIGN_DSA_NSEC3, "NSEC3DSA"}, {LDNS_SIGN_RSASHA1_NSEC3, "NSEC3RSASHA1"}, /* old ldns usage, now RFC names */ {LDNS_SIGN_DSA_NSEC3, "DSA_NSEC3" }, {LDNS_SIGN_RSASHA1_NSEC3, "RSASHA1_NSEC3" }, #ifdef USE_GOST {LDNS_SIGN_ECC_GOST, "GOST"}, #endif /* compat with possible output */ {LDNS_DH, "DH"}, {LDNS_ECC, "ECC"}, {LDNS_INDIRECT, "INDIRECT"}, {LDNS_PRIVATEDNS, "PRIVATEDNS"}, {LDNS_PRIVATEOID, "PRIVATEOID"}, {0, NULL}}; ldns_lookup_table* lt = ldns_signing_algorithms; ldns_signing_algorithm a; char *endptr; while(lt->name) { if(strcasecmp(lt->name, name) == 0) return lt->id; lt++; } lt = aliases; while(lt->name) { if(strcasecmp(lt->name, name) == 0) return lt->id; lt++; } a = strtol(name, &endptr, 10); if (*name && !*endptr) return a; return 0; } Net-LDNS-0.75/src/ldns/net.c000644 000770 000024 00000056047 12471046240 016011 0ustar00calledstaff000000 000000 /* * net.c * * Network implementation * All network related functions are grouped here * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #include #include #include ldns_status ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt) { ldns_buffer *qb; ldns_status result; ldns_rdf *tsig_mac = NULL; qb = ldns_buffer_new(LDNS_MIN_BUFLEN); if (query_pkt && ldns_pkt_tsig(query_pkt)) { tsig_mac = ldns_rr_rdf(ldns_pkt_tsig(query_pkt), 3); } if (!query_pkt || ldns_pkt2buffer_wire(qb, query_pkt) != LDNS_STATUS_OK) { result = LDNS_STATUS_ERR; } else { result = ldns_send_buffer(result_packet, r, qb, tsig_mac); } ldns_buffer_free(qb); return result; } /* code from rdata.c */ static struct sockaddr_storage * ldns_rdf2native_sockaddr_storage_port( const ldns_rdf *rd, uint16_t port, size_t *size) { struct sockaddr_storage *data; struct sockaddr_in *data_in; struct sockaddr_in6 *data_in6; data = LDNS_MALLOC(struct sockaddr_storage); if (!data) { return NULL; } /* zero the structure for portability */ memset(data, 0, sizeof(struct sockaddr_storage)); switch(ldns_rdf_get_type(rd)) { case LDNS_RDF_TYPE_A: #ifndef S_SPLINT_S data->ss_family = AF_INET; #endif data_in = (struct sockaddr_in*) data; data_in->sin_port = (in_port_t)htons(port); memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd)); *size = sizeof(struct sockaddr_in); return data; case LDNS_RDF_TYPE_AAAA: #ifndef S_SPLINT_S data->ss_family = AF_INET6; #endif data_in6 = (struct sockaddr_in6*) data; data_in6->sin6_port = (in_port_t)htons(port); memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd)); *size = sizeof(struct sockaddr_in6); return data; default: LDNS_FREE(data); return NULL; } } struct sockaddr_storage * ldns_rdf2native_sockaddr_storage( const ldns_rdf *rd, uint16_t port, size_t *size) { return ldns_rdf2native_sockaddr_storage_port( rd, (port == 0 ? (uint16_t)LDNS_PORT : port), size); } /** best effort to set nonblocking */ static void ldns_sock_nonblock(int sockfd) { #ifdef HAVE_FCNTL int flag; if((flag = fcntl(sockfd, F_GETFL)) != -1) { flag |= O_NONBLOCK; if(fcntl(sockfd, F_SETFL, flag) == -1) { /* ignore error, continue blockingly */ } } #elif defined(HAVE_IOCTLSOCKET) unsigned long on = 1; if(ioctlsocket(sockfd, FIONBIO, &on) != 0) { /* ignore error, continue blockingly */ } #endif } /** best effort to set blocking */ static void ldns_sock_block(int sockfd) { #ifdef HAVE_FCNTL int flag; if((flag = fcntl(sockfd, F_GETFL)) != -1) { flag &= ~O_NONBLOCK; if(fcntl(sockfd, F_SETFL, flag) == -1) { /* ignore error, continue */ } } #elif defined(HAVE_IOCTLSOCKET) unsigned long off = 0; if(ioctlsocket(sockfd, FIONBIO, &off) != 0) { /* ignore error, continue */ } #endif } /** wait for a socket to become ready */ static int ldns_sock_wait(int sockfd, struct timeval timeout, int write) { int ret; #ifndef S_SPLINT_S fd_set fds; FD_ZERO(&fds); FD_SET(FD_SET_T sockfd, &fds); if(write) ret = select(sockfd+1, NULL, &fds, NULL, &timeout); else ret = select(sockfd+1, &fds, NULL, NULL, &timeout); #endif if(ret == 0) /* timeout expired */ return 0; else if(ret == -1) /* error */ return 0; return 1; } static int ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen, const struct sockaddr_storage *from, socklen_t fromlen, struct timeval timeout) { int sockfd; #ifndef S_SPLINT_S if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { return 0; } #endif if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){ return 0; } /* perform nonblocking connect, to be able to wait with select() */ ldns_sock_nonblock(sockfd); if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) { #ifndef USE_WINSOCK #ifdef EINPROGRESS if(errno != EINPROGRESS) { #else if(1) { #endif close(sockfd); return 0; } #else /* USE_WINSOCK */ if(WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK) { closesocket(sockfd); return 0; } #endif /* error was only telling us that it would block */ } /* wait(write) until connected or error */ while(1) { int error = 0; socklen_t len = (socklen_t)sizeof(error); if(!ldns_sock_wait(sockfd, timeout, 1)) { #ifndef USE_WINSOCK close(sockfd); #else closesocket(sockfd); #endif return 0; } /* check if there is a pending error for nonblocking connect */ if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error, &len) < 0) { #ifndef USE_WINSOCK error = errno; /* on solaris errno is error */ #else error = WSAGetLastError(); #endif } #ifndef USE_WINSOCK #if defined(EINPROGRESS) && defined(EWOULDBLOCK) if(error == EINPROGRESS || error == EWOULDBLOCK) continue; /* try again */ #endif else if(error != 0) { close(sockfd); /* error in errno for our user */ errno = error; return 0; } #else /* USE_WINSOCK */ if(error == WSAEINPROGRESS) continue; else if(error == WSAEWOULDBLOCK) continue; else if(error != 0) { closesocket(sockfd); errno = error; return 0; } #endif /* USE_WINSOCK */ /* connected */ break; } /* set the socket blocking again */ ldns_sock_block(sockfd); return sockfd; } int ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout) { return ldns_tcp_connect_from(to, tolen, NULL, 0, timeout); } static int ldns_tcp_bgsend_from(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, const struct sockaddr_storage *from, socklen_t fromlen, struct timeval timeout) { int sockfd; sockfd = ldns_tcp_connect_from(to, tolen, from, fromlen, timeout); if (sockfd == 0) { return 0; } if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) { #ifndef USE_WINSOCK close(sockfd); #else closesocket(sockfd); #endif return 0; } return sockfd; } int ldns_tcp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout) { return ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout); } /* keep in mind that in DNS tcp messages the first 2 bytes signal the * amount data to expect */ static ldns_status ldns_tcp_send_from(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, const struct sockaddr_storage *from, socklen_t fromlen, struct timeval timeout, size_t *answer_size) { int sockfd; uint8_t *answer; sockfd = ldns_tcp_bgsend_from(qbin, to, tolen, from, fromlen, timeout); if (sockfd == 0) { return LDNS_STATUS_ERR; } answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout); #ifndef USE_WINSOCK close(sockfd); #else closesocket(sockfd); #endif if (*answer_size == 0) { /* oops */ return LDNS_STATUS_NETWORK_ERR; } /* resize accordingly */ *result = LDNS_XREALLOC(answer, uint8_t, (size_t)*answer_size); if(!*result) { LDNS_FREE(answer); return LDNS_STATUS_MEM_ERR; } return LDNS_STATUS_OK; } ldns_status ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout, size_t *answer_size) { return ldns_tcp_send_from(result, qbin, to, tolen, NULL, 0, timeout, answer_size); } int ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout)) { int sockfd; #ifndef S_SPLINT_S if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) { return 0; } #endif return sockfd; } static int ldns_udp_bgsend_from(ldns_buffer *qbin, const struct sockaddr_storage *to , socklen_t tolen, const struct sockaddr_storage *from, socklen_t fromlen, struct timeval timeout) { int sockfd; sockfd = ldns_udp_connect(to, timeout); if (sockfd == 0) { return 0; } if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){ return 0; } if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) { #ifndef USE_WINSOCK close(sockfd); #else closesocket(sockfd); #endif return 0; } return sockfd; } int ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to , socklen_t tolen, struct timeval timeout) { return ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout); } static ldns_status ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to , socklen_t tolen, const struct sockaddr_storage *from, socklen_t fromlen, struct timeval timeout, size_t *answer_size) { int sockfd; uint8_t *answer; sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout); if (sockfd == 0) { return LDNS_STATUS_SOCKET_ERROR; } /* wait for an response*/ if(!ldns_sock_wait(sockfd, timeout, 0)) { #ifndef USE_WINSOCK close(sockfd); #else closesocket(sockfd); #endif return LDNS_STATUS_NETWORK_ERR; } /* set to nonblocking, so if the checksum is bad, it becomes * an EGAIN error and the ldns_udp_send function does not block, * but returns a 'NETWORK_ERROR' much like a timeout. */ ldns_sock_nonblock(sockfd); answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL); #ifndef USE_WINSOCK close(sockfd); #else closesocket(sockfd); #endif if (*answer_size == 0) { /* oops */ return LDNS_STATUS_NETWORK_ERR; } *result = answer; return LDNS_STATUS_OK; } ldns_status ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to , socklen_t tolen, struct timeval timeout, size_t *answer_size) { return ldns_udp_send_from(result, qbin, to, tolen, NULL, 0, timeout, answer_size); } ldns_status ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac) { uint8_t i; struct sockaddr_storage *src = NULL; size_t src_len; struct sockaddr_storage *ns; size_t ns_len; struct timeval tv_s; struct timeval tv_e; ldns_rdf **ns_array; size_t *rtt; ldns_pkt *reply; bool all_servers_rtt_inf; uint8_t retries; uint8_t *reply_bytes = NULL; size_t reply_size = 0; ldns_status status, send_status; assert(r != NULL); status = LDNS_STATUS_OK; rtt = ldns_resolver_rtt(r); ns_array = ldns_resolver_nameservers(r); reply = NULL; ns_len = 0; all_servers_rtt_inf = true; if (ldns_resolver_random(r)) { ldns_resolver_nameservers_randomize(r); } if(ldns_resolver_source(r)) { src = ldns_rdf2native_sockaddr_storage_port( ldns_resolver_source(r), 0, &src_len); } /* loop through all defined nameservers */ for (i = 0; i < ldns_resolver_nameserver_count(r); i++) { if (rtt[i] == LDNS_RESOLV_RTT_INF) { /* not reachable nameserver! */ continue; } /* maybe verbosity setting? printf("Sending to "); ldns_rdf_print(stdout, ns_array[i]); printf("\n"); */ ns = ldns_rdf2native_sockaddr_storage(ns_array[i], ldns_resolver_port(r), &ns_len); #ifndef S_SPLINT_S if ((ns->ss_family == AF_INET) && (ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) { /* not reachable */ LDNS_FREE(ns); continue; } if ((ns->ss_family == AF_INET6) && (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) { /* not reachable */ LDNS_FREE(ns); continue; } #endif all_servers_rtt_inf = false; gettimeofday(&tv_s, NULL); send_status = LDNS_STATUS_ERR; /* reply_bytes implicitly handles our error */ if (ldns_resolver_usevc(r)) { for (retries = ldns_resolver_retry(r); retries > 0; retries--) { send_status = ldns_tcp_send_from(&reply_bytes, qb, ns, (socklen_t)ns_len, src, (socklen_t)src_len, ldns_resolver_timeout(r), &reply_size); if (send_status == LDNS_STATUS_OK) { break; } } } else { for (retries = ldns_resolver_retry(r); retries > 0; retries--) { /* ldns_rdf_print(stdout, ns_array[i]); */ send_status = ldns_udp_send_from(&reply_bytes, qb, ns, (socklen_t)ns_len, src, (socklen_t)src_len, ldns_resolver_timeout(r), &reply_size); if (send_status == LDNS_STATUS_OK) { break; } } } if (send_status != LDNS_STATUS_OK) { ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF); status = send_status; } /* obey the fail directive */ if (!reply_bytes) { /* the current nameserver seems to have a problem, blacklist it */ if (ldns_resolver_fail(r)) { LDNS_FREE(ns); return LDNS_STATUS_ERR; } else { LDNS_FREE(ns); continue; } } status = ldns_wire2pkt(&reply, reply_bytes, reply_size); if (status != LDNS_STATUS_OK) { LDNS_FREE(reply_bytes); LDNS_FREE(ns); return status; } LDNS_FREE(ns); gettimeofday(&tv_e, NULL); if (reply) { ldns_pkt_set_querytime(reply, (uint32_t) ((tv_e.tv_sec - tv_s.tv_sec) * 1000) + (tv_e.tv_usec - tv_s.tv_usec) / 1000); ldns_pkt_set_answerfrom(reply, ldns_rdf_clone(ns_array[i])); ldns_pkt_set_timestamp(reply, tv_s); ldns_pkt_set_size(reply, reply_size); break; } else { if (ldns_resolver_fail(r)) { /* if fail is set bail out, after the first * one */ break; } } /* wait retrans seconds... */ sleep((unsigned int) ldns_resolver_retrans(r)); } if(src) { LDNS_FREE(src); } if (all_servers_rtt_inf) { LDNS_FREE(reply_bytes); return LDNS_STATUS_RES_NO_NS; } #ifdef HAVE_SSL if (tsig_mac && reply && reply_bytes) { if (!ldns_pkt_tsig_verify(reply, reply_bytes, reply_size, ldns_resolver_tsig_keyname(r), ldns_resolver_tsig_keydata(r), tsig_mac)) { status = LDNS_STATUS_CRYPTO_TSIG_BOGUS; } } #else (void)tsig_mac; #endif /* HAVE_SSL */ LDNS_FREE(reply_bytes); if (result) { *result = reply; } return status; } ssize_t ldns_tcp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen) { uint8_t *sendbuf; ssize_t bytes; /* add length of packet */ sendbuf = LDNS_XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2); if(!sendbuf) return 0; ldns_write_uint16(sendbuf, ldns_buffer_position(qbin)); memcpy(sendbuf + 2, ldns_buffer_begin(qbin), ldns_buffer_position(qbin)); bytes = sendto(sockfd, (void*)sendbuf, ldns_buffer_position(qbin) + 2, 0, (struct sockaddr *)to, tolen); LDNS_FREE(sendbuf); if (bytes == -1 || (size_t) bytes != ldns_buffer_position(qbin) + 2 ) { return 0; } return bytes; } /* don't wait for an answer */ ssize_t ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen) { ssize_t bytes; bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin), ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen); if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) { return 0; } if ((size_t) bytes != ldns_buffer_position(qbin)) { return 0; } return bytes; } uint8_t * ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from, socklen_t *fromlen) { uint8_t *wire, *wireout; ssize_t wire_size; wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN); if (!wire) { *size = 0; return NULL; } wire_size = recvfrom(sockfd, (void*)wire, LDNS_MAX_PACKETLEN, 0, (struct sockaddr *)from, fromlen); /* recvfrom can also return 0 */ if (wire_size == -1 || wire_size == 0) { *size = 0; LDNS_FREE(wire); return NULL; } *size = (size_t)wire_size; wireout = LDNS_XREALLOC(wire, uint8_t, (size_t)wire_size); if(!wireout) LDNS_FREE(wire); return wireout; } uint8_t * ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout) { uint8_t *wire; uint16_t wire_size; ssize_t bytes = 0, rc = 0; wire = LDNS_XMALLOC(uint8_t, 2); if (!wire) { *size = 0; return NULL; } while (bytes < 2) { if(!ldns_sock_wait(sockfd, timeout, 0)) { *size = 0; LDNS_FREE(wire); return NULL; } rc = recv(sockfd, (void*) (wire + bytes), (size_t) (2 - bytes), 0); if (rc == -1 || rc == 0) { *size = 0; LDNS_FREE(wire); return NULL; } bytes += rc; } wire_size = ldns_read_uint16(wire); LDNS_FREE(wire); wire = LDNS_XMALLOC(uint8_t, wire_size); if (!wire) { *size = 0; return NULL; } bytes = 0; while (bytes < (ssize_t) wire_size) { if(!ldns_sock_wait(sockfd, timeout, 0)) { *size = 0; LDNS_FREE(wire); return NULL; } rc = recv(sockfd, (void*) (wire + bytes), (size_t) (wire_size - bytes), 0); if (rc == -1 || rc == 0) { LDNS_FREE(wire); *size = 0; return NULL; } bytes += rc; } *size = (size_t) bytes; return wire; } uint8_t * ldns_tcp_read_wire(int sockfd, size_t *size) { uint8_t *wire; uint16_t wire_size; ssize_t bytes = 0, rc = 0; wire = LDNS_XMALLOC(uint8_t, 2); if (!wire) { *size = 0; return NULL; } while (bytes < 2) { rc = recv(sockfd, (void*) (wire + bytes), (size_t) (2 - bytes), 0); if (rc == -1 || rc == 0) { *size = 0; LDNS_FREE(wire); return NULL; } bytes += rc; } wire_size = ldns_read_uint16(wire); LDNS_FREE(wire); wire = LDNS_XMALLOC(uint8_t, wire_size); if (!wire) { *size = 0; return NULL; } bytes = 0; while (bytes < (ssize_t) wire_size) { rc = recv(sockfd, (void*) (wire + bytes), (size_t) (wire_size - bytes), 0); if (rc == -1 || rc == 0) { LDNS_FREE(wire); *size = 0; return NULL; } bytes += rc; } *size = (size_t) bytes; return wire; } #ifndef S_SPLINT_S ldns_rdf * ldns_sockaddr_storage2rdf(struct sockaddr_storage *sock, uint16_t *port) { ldns_rdf *addr; struct sockaddr_in *data_in; struct sockaddr_in6 *data_in6; switch(sock->ss_family) { case AF_INET: data_in = (struct sockaddr_in*)sock; if (port) { *port = ntohs((uint16_t)data_in->sin_port); } addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_A, LDNS_IP4ADDRLEN, &data_in->sin_addr); break; case AF_INET6: data_in6 = (struct sockaddr_in6*)sock; if (port) { *port = ntohs((uint16_t)data_in6->sin6_port); } addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_AAAA, LDNS_IP6ADDRLEN, &data_in6->sin6_addr); break; default: if (port) { *port = 0; } return NULL; } return addr; } #endif /* code from resolver.c */ ldns_status ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class) { ldns_pkt *query; ldns_buffer *query_wire; struct sockaddr_storage *src = NULL; size_t src_len = 0; struct sockaddr_storage *ns = NULL; size_t ns_len = 0; size_t ns_i; ldns_status status; if (!resolver || ldns_resolver_nameserver_count(resolver) < 1) { return LDNS_STATUS_ERR; } query = ldns_pkt_query_new(ldns_rdf_clone(domain), LDNS_RR_TYPE_AXFR, class, 0); if (!query) { return LDNS_STATUS_ADDRESS_ERR; } if(ldns_resolver_source(resolver)) { src = ldns_rdf2native_sockaddr_storage_port( ldns_resolver_source(resolver), 0, &src_len); } /* For AXFR, we have to make the connection ourselves */ /* try all nameservers (which usually would mean v4 fallback if * @hostname is used */ for (ns_i = 0; ns_i < ldns_resolver_nameserver_count(resolver) && resolver->_socket == 0; ns_i++) { if (ns != NULL) { LDNS_FREE(ns); } ns = ldns_rdf2native_sockaddr_storage( resolver->_nameservers[ns_i], ldns_resolver_port(resolver), &ns_len); resolver->_socket = ldns_tcp_connect_from( ns, (socklen_t)ns_len, src, (socklen_t)src_len, ldns_resolver_timeout(resolver)); } if (resolver->_socket == 0) { ldns_pkt_free(query); LDNS_FREE(ns); return LDNS_STATUS_NETWORK_ERR; } #ifdef HAVE_SSL if (ldns_resolver_tsig_keyname(resolver) && ldns_resolver_tsig_keydata(resolver)) { status = ldns_pkt_tsig_sign(query, ldns_resolver_tsig_keyname(resolver), ldns_resolver_tsig_keydata(resolver), 300, ldns_resolver_tsig_algorithm(resolver), NULL); if (status != LDNS_STATUS_OK) { /* to prevent problems on subsequent calls to * ldns_axfr_start we have to close the socket here! */ #ifndef USE_WINSOCK close(resolver->_socket); #else closesocket(resolver->_socket); #endif resolver->_socket = 0; ldns_pkt_free(query); LDNS_FREE(ns); return LDNS_STATUS_CRYPTO_TSIG_ERR; } } #endif /* HAVE_SSL */ /* Convert the query to a buffer * Is this necessary? */ query_wire = ldns_buffer_new(LDNS_MAX_PACKETLEN); if(!query_wire) { ldns_pkt_free(query); LDNS_FREE(ns); #ifndef USE_WINSOCK close(resolver->_socket); #else closesocket(resolver->_socket); #endif resolver->_socket = 0; return LDNS_STATUS_MEM_ERR; } status = ldns_pkt2buffer_wire(query_wire, query); if (status != LDNS_STATUS_OK) { ldns_pkt_free(query); ldns_buffer_free(query_wire); LDNS_FREE(ns); /* to prevent problems on subsequent calls to ldns_axfr_start * we have to close the socket here! */ #ifndef USE_WINSOCK close(resolver->_socket); #else closesocket(resolver->_socket); #endif resolver->_socket = 0; return status; } /* Send the query */ if (ldns_tcp_send_query(query_wire, resolver->_socket, ns, (socklen_t)ns_len) == 0) { ldns_pkt_free(query); ldns_buffer_free(query_wire); LDNS_FREE(ns); /* to prevent problems on subsequent calls to ldns_axfr_start * we have to close the socket here! */ #ifndef USE_WINSOCK close(resolver->_socket); #else closesocket(resolver->_socket); #endif resolver->_socket = 0; return LDNS_STATUS_NETWORK_ERR; } ldns_pkt_free(query); ldns_buffer_free(query_wire); LDNS_FREE(ns); /* * The AXFR is done once the second SOA record is sent */ resolver->_axfr_soa_count = 0; return LDNS_STATUS_OK; } Net-LDNS-0.75/src/ldns/packet.c000644 000770 000024 00000060337 12471046240 016467 0ustar00calledstaff000000 000000 /* * packet.c * * dns packet implementation * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include #include #include #ifdef HAVE_SSL #include #endif /* Access functions * do this as functions to get type checking */ #define LDNS_EDNS_MASK_DO_BIT 0x8000 /* TODO defines for 3600 */ /* convert to and from numerical flag values */ ldns_lookup_table ldns_edns_flags[] = { { 3600, "do"}, { 0, NULL} }; /* read */ uint16_t ldns_pkt_id(const ldns_pkt *packet) { return packet->_header->_id; } bool ldns_pkt_qr(const ldns_pkt *packet) { return packet->_header->_qr; } bool ldns_pkt_aa(const ldns_pkt *packet) { return packet->_header->_aa; } bool ldns_pkt_tc(const ldns_pkt *packet) { return packet->_header->_tc; } bool ldns_pkt_rd(const ldns_pkt *packet) { return packet->_header->_rd; } bool ldns_pkt_cd(const ldns_pkt *packet) { return packet->_header->_cd; } bool ldns_pkt_ra(const ldns_pkt *packet) { return packet->_header->_ra; } bool ldns_pkt_ad(const ldns_pkt *packet) { return packet->_header->_ad; } ldns_pkt_opcode ldns_pkt_get_opcode(const ldns_pkt *packet) { return packet->_header->_opcode; } ldns_pkt_rcode ldns_pkt_get_rcode(const ldns_pkt *packet) { return packet->_header->_rcode; } uint16_t ldns_pkt_qdcount(const ldns_pkt *packet) { return packet->_header->_qdcount; } uint16_t ldns_pkt_ancount(const ldns_pkt *packet) { return packet->_header->_ancount; } uint16_t ldns_pkt_nscount(const ldns_pkt *packet) { return packet->_header->_nscount; } uint16_t ldns_pkt_arcount(const ldns_pkt *packet) { return packet->_header->_arcount; } ldns_rr_list * ldns_pkt_question(const ldns_pkt *packet) { return packet->_question; } ldns_rr_list * ldns_pkt_answer(const ldns_pkt *packet) { return packet->_answer; } ldns_rr_list * ldns_pkt_authority(const ldns_pkt *packet) { return packet->_authority; } ldns_rr_list * ldns_pkt_additional(const ldns_pkt *packet) { return packet->_additional; } /* return ALL section concatenated */ ldns_rr_list * ldns_pkt_all(const ldns_pkt *packet) { ldns_rr_list *all, *prev_all; all = ldns_rr_list_cat_clone( ldns_pkt_question(packet), ldns_pkt_answer(packet)); prev_all = all; all = ldns_rr_list_cat_clone(all, ldns_pkt_authority(packet)); ldns_rr_list_deep_free(prev_all); prev_all = all; all = ldns_rr_list_cat_clone(all, ldns_pkt_additional(packet)); ldns_rr_list_deep_free(prev_all); return all; } ldns_rr_list * ldns_pkt_all_noquestion(const ldns_pkt *packet) { ldns_rr_list *all, *all2; all = ldns_rr_list_cat_clone( ldns_pkt_answer(packet), ldns_pkt_authority(packet)); all2 = ldns_rr_list_cat_clone(all, ldns_pkt_additional(packet)); ldns_rr_list_deep_free(all); return all2; } size_t ldns_pkt_size(const ldns_pkt *packet) { return packet->_size; } uint32_t ldns_pkt_querytime(const ldns_pkt *packet) { return packet->_querytime; } ldns_rdf * ldns_pkt_answerfrom(const ldns_pkt *packet) { return packet->_answerfrom; } struct timeval ldns_pkt_timestamp(const ldns_pkt *packet) { return packet->timestamp; } uint16_t ldns_pkt_edns_udp_size(const ldns_pkt *packet) { return packet->_edns_udp_size; } uint8_t ldns_pkt_edns_extended_rcode(const ldns_pkt *packet) { return packet->_edns_extended_rcode; } uint8_t ldns_pkt_edns_version(const ldns_pkt *packet) { return packet->_edns_version; } uint16_t ldns_pkt_edns_z(const ldns_pkt *packet) { return packet->_edns_z; } bool ldns_pkt_edns_do(const ldns_pkt *packet) { return (packet->_edns_z & LDNS_EDNS_MASK_DO_BIT); } void ldns_pkt_set_edns_do(ldns_pkt *packet, bool value) { if (value) { packet->_edns_z = packet->_edns_z | LDNS_EDNS_MASK_DO_BIT; } else { packet->_edns_z = packet->_edns_z & ~LDNS_EDNS_MASK_DO_BIT; } } ldns_rdf * ldns_pkt_edns_data(const ldns_pkt *packet) { return packet->_edns_data; } /* return only those rr that share the ownername */ ldns_rr_list * ldns_pkt_rr_list_by_name(ldns_pkt *packet, ldns_rdf *ownername, ldns_pkt_section sec) { ldns_rr_list *rrs; ldns_rr_list *ret; uint16_t i; if (!packet) { return NULL; } rrs = ldns_pkt_get_section_clone(packet, sec); ret = NULL; for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { if (ldns_dname_compare(ldns_rr_owner( ldns_rr_list_rr(rrs, i)), ownername) == 0) { /* owner names match */ if (ret == NULL) { ret = ldns_rr_list_new(); } ldns_rr_list_push_rr(ret, ldns_rr_clone( ldns_rr_list_rr(rrs, i)) ); } } ldns_rr_list_deep_free(rrs); return ret; } /* return only those rr that share a type */ ldns_rr_list * ldns_pkt_rr_list_by_type(const ldns_pkt *packet, ldns_rr_type type, ldns_pkt_section sec) { ldns_rr_list *rrs; ldns_rr_list *new; uint16_t i; if(!packet) { return NULL; } rrs = ldns_pkt_get_section_clone(packet, sec); new = ldns_rr_list_new(); for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i))) { /* types match */ ldns_rr_list_push_rr(new, ldns_rr_clone( ldns_rr_list_rr(rrs, i)) ); } } ldns_rr_list_deep_free(rrs); if (ldns_rr_list_rr_count(new) == 0) { ldns_rr_list_free(new); return NULL; } else { return new; } } /* return only those rrs that share name and type */ ldns_rr_list * ldns_pkt_rr_list_by_name_and_type(const ldns_pkt *packet, const ldns_rdf *ownername, ldns_rr_type type, ldns_pkt_section sec) { ldns_rr_list *rrs; ldns_rr_list *new; ldns_rr_list *ret; uint16_t i; if(!packet) { return NULL; } rrs = ldns_pkt_get_section_clone(packet, sec); new = ldns_rr_list_new(); ret = NULL; for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i)) && ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(rrs, i)), ownername ) == 0 ) { /* types match */ ldns_rr_list_push_rr(new, ldns_rr_clone(ldns_rr_list_rr(rrs, i))); ret = new; } } ldns_rr_list_deep_free(rrs); if (!ret) { ldns_rr_list_free(new); } return ret; } bool ldns_pkt_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr) { bool result = false; switch (sec) { case LDNS_SECTION_QUESTION: return ldns_rr_list_contains_rr(ldns_pkt_question(pkt), rr); case LDNS_SECTION_ANSWER: return ldns_rr_list_contains_rr(ldns_pkt_answer(pkt), rr); case LDNS_SECTION_AUTHORITY: return ldns_rr_list_contains_rr(ldns_pkt_authority(pkt), rr); case LDNS_SECTION_ADDITIONAL: return ldns_rr_list_contains_rr(ldns_pkt_additional(pkt), rr); case LDNS_SECTION_ANY: result = ldns_rr_list_contains_rr(ldns_pkt_question(pkt), rr); case LDNS_SECTION_ANY_NOQUESTION: result = result || ldns_rr_list_contains_rr(ldns_pkt_answer(pkt), rr) || ldns_rr_list_contains_rr(ldns_pkt_authority(pkt), rr) || ldns_rr_list_contains_rr(ldns_pkt_additional(pkt), rr); } return result; } uint16_t ldns_pkt_section_count(const ldns_pkt *packet, ldns_pkt_section s) { switch(s) { case LDNS_SECTION_QUESTION: return ldns_pkt_qdcount(packet); case LDNS_SECTION_ANSWER: return ldns_pkt_ancount(packet); case LDNS_SECTION_AUTHORITY: return ldns_pkt_nscount(packet); case LDNS_SECTION_ADDITIONAL: return ldns_pkt_arcount(packet); case LDNS_SECTION_ANY: return ldns_pkt_qdcount(packet) + ldns_pkt_ancount(packet) + ldns_pkt_nscount(packet) + ldns_pkt_arcount(packet); case LDNS_SECTION_ANY_NOQUESTION: return ldns_pkt_ancount(packet) + ldns_pkt_nscount(packet) + ldns_pkt_arcount(packet); default: return 0; } } bool ldns_pkt_empty(ldns_pkt *p) { if (!p) { return true; /* NULL is empty? */ } if (ldns_pkt_section_count(p, LDNS_SECTION_ANY) > 0) { return false; } else { return true; } } ldns_rr_list * ldns_pkt_get_section_clone(const ldns_pkt *packet, ldns_pkt_section s) { switch(s) { case LDNS_SECTION_QUESTION: return ldns_rr_list_clone(ldns_pkt_question(packet)); case LDNS_SECTION_ANSWER: return ldns_rr_list_clone(ldns_pkt_answer(packet)); case LDNS_SECTION_AUTHORITY: return ldns_rr_list_clone(ldns_pkt_authority(packet)); case LDNS_SECTION_ADDITIONAL: return ldns_rr_list_clone(ldns_pkt_additional(packet)); case LDNS_SECTION_ANY: /* these are already clones */ return ldns_pkt_all(packet); case LDNS_SECTION_ANY_NOQUESTION: return ldns_pkt_all_noquestion(packet); default: return NULL; } } ldns_rr *ldns_pkt_tsig(const ldns_pkt *pkt) { return pkt->_tsig_rr; } /* write */ void ldns_pkt_set_id(ldns_pkt *packet, uint16_t id) { packet->_header->_id = id; } void ldns_pkt_set_random_id(ldns_pkt *packet) { uint16_t rid = ldns_get_random(); ldns_pkt_set_id(packet, rid); } void ldns_pkt_set_qr(ldns_pkt *packet, bool qr) { packet->_header->_qr = qr; } void ldns_pkt_set_aa(ldns_pkt *packet, bool aa) { packet->_header->_aa = aa; } void ldns_pkt_set_tc(ldns_pkt *packet, bool tc) { packet->_header->_tc = tc; } void ldns_pkt_set_rd(ldns_pkt *packet, bool rd) { packet->_header->_rd = rd; } void ldns_pkt_set_additional(ldns_pkt *p, ldns_rr_list *rr) { p->_additional = rr; } void ldns_pkt_set_question(ldns_pkt *p, ldns_rr_list *rr) { p->_question = rr; } void ldns_pkt_set_answer(ldns_pkt *p, ldns_rr_list *rr) { p->_answer = rr; } void ldns_pkt_set_authority(ldns_pkt *p, ldns_rr_list *rr) { p->_authority = rr; } void ldns_pkt_set_cd(ldns_pkt *packet, bool cd) { packet->_header->_cd = cd; } void ldns_pkt_set_ra(ldns_pkt *packet, bool ra) { packet->_header->_ra = ra; } void ldns_pkt_set_ad(ldns_pkt *packet, bool ad) { packet->_header->_ad = ad; } void ldns_pkt_set_opcode(ldns_pkt *packet, ldns_pkt_opcode opcode) { packet->_header->_opcode = opcode; } void ldns_pkt_set_rcode(ldns_pkt *packet, uint8_t rcode) { packet->_header->_rcode = rcode; } void ldns_pkt_set_qdcount(ldns_pkt *packet, uint16_t qdcount) { packet->_header->_qdcount = qdcount; } void ldns_pkt_set_ancount(ldns_pkt *packet, uint16_t ancount) { packet->_header->_ancount = ancount; } void ldns_pkt_set_nscount(ldns_pkt *packet, uint16_t nscount) { packet->_header->_nscount = nscount; } void ldns_pkt_set_arcount(ldns_pkt *packet, uint16_t arcount) { packet->_header->_arcount = arcount; } void ldns_pkt_set_querytime(ldns_pkt *packet, uint32_t time) { packet->_querytime = time; } void ldns_pkt_set_answerfrom(ldns_pkt *packet, ldns_rdf *answerfrom) { packet->_answerfrom = answerfrom; } void ldns_pkt_set_timestamp(ldns_pkt *packet, struct timeval timeval) { packet->timestamp.tv_sec = timeval.tv_sec; packet->timestamp.tv_usec = timeval.tv_usec; } void ldns_pkt_set_size(ldns_pkt *packet, size_t s) { packet->_size = s; } void ldns_pkt_set_edns_udp_size(ldns_pkt *packet, uint16_t s) { packet->_edns_udp_size = s; } void ldns_pkt_set_edns_extended_rcode(ldns_pkt *packet, uint8_t c) { packet->_edns_extended_rcode = c; } void ldns_pkt_set_edns_version(ldns_pkt *packet, uint8_t v) { packet->_edns_version = v; } void ldns_pkt_set_edns_z(ldns_pkt *packet, uint16_t z) { packet->_edns_z = z; } void ldns_pkt_set_edns_data(ldns_pkt *packet, ldns_rdf *data) { packet->_edns_data = data; } void ldns_pkt_set_section_count(ldns_pkt *packet, ldns_pkt_section s, uint16_t count) { switch(s) { case LDNS_SECTION_QUESTION: ldns_pkt_set_qdcount(packet, count); break; case LDNS_SECTION_ANSWER: ldns_pkt_set_ancount(packet, count); break; case LDNS_SECTION_AUTHORITY: ldns_pkt_set_nscount(packet, count); break; case LDNS_SECTION_ADDITIONAL: ldns_pkt_set_arcount(packet, count); break; case LDNS_SECTION_ANY: case LDNS_SECTION_ANY_NOQUESTION: break; } } void ldns_pkt_set_tsig(ldns_pkt *pkt, ldns_rr *rr) { pkt->_tsig_rr = rr; } bool ldns_pkt_push_rr(ldns_pkt *packet, ldns_pkt_section section, ldns_rr *rr) { switch(section) { case LDNS_SECTION_QUESTION: if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) { return false; } ldns_pkt_set_qdcount(packet, ldns_pkt_qdcount(packet) + 1); break; case LDNS_SECTION_ANSWER: if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) { return false; } ldns_pkt_set_ancount(packet, ldns_pkt_ancount(packet) + 1); break; case LDNS_SECTION_AUTHORITY: if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) { return false; } ldns_pkt_set_nscount(packet, ldns_pkt_nscount(packet) + 1); break; case LDNS_SECTION_ADDITIONAL: if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) { return false; } ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) + 1); break; case LDNS_SECTION_ANY: case LDNS_SECTION_ANY_NOQUESTION: /* shouldn't this error? */ break; } return true; } bool ldns_pkt_safe_push_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr) { /* check to see if its there */ if (ldns_pkt_rr(pkt, sec, rr)) { /* already there */ return false; } return ldns_pkt_push_rr(pkt, sec, rr); } bool ldns_pkt_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list) { size_t i; for(i = 0; i < ldns_rr_list_rr_count(list); i++) { if (!ldns_pkt_push_rr(p, s, ldns_rr_list_rr(list, i))) { return false; } } return true; } bool ldns_pkt_safe_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list) { size_t i; for(i = 0; i < ldns_rr_list_rr_count(list); i++) { if (!ldns_pkt_safe_push_rr(p, s, ldns_rr_list_rr(list, i))) { return false; } } return true; } bool ldns_pkt_edns(const ldns_pkt *pkt) { return (ldns_pkt_edns_udp_size(pkt) > 0 || ldns_pkt_edns_extended_rcode(pkt) > 0 || ldns_pkt_edns_data(pkt) || ldns_pkt_edns_do(pkt) || pkt->_edns_present ); } /* Create/destroy/convert functions */ ldns_pkt * ldns_pkt_new(void) { ldns_pkt *packet; packet = LDNS_MALLOC(ldns_pkt); if (!packet) { return NULL; } packet->_header = LDNS_MALLOC(ldns_hdr); if (!packet->_header) { LDNS_FREE(packet); return NULL; } packet->_question = ldns_rr_list_new(); packet->_answer = ldns_rr_list_new(); packet->_authority = ldns_rr_list_new(); packet->_additional = ldns_rr_list_new(); /* default everything to false */ ldns_pkt_set_qr(packet, false); ldns_pkt_set_aa(packet, false); ldns_pkt_set_tc(packet, false); ldns_pkt_set_rd(packet, false); ldns_pkt_set_ra(packet, false); ldns_pkt_set_ad(packet, false); ldns_pkt_set_cd(packet, false); ldns_pkt_set_opcode(packet, LDNS_PACKET_QUERY); ldns_pkt_set_rcode(packet, 0); ldns_pkt_set_id(packet, 0); ldns_pkt_set_size(packet, 0); ldns_pkt_set_querytime(packet, 0); memset(&packet->timestamp, 0, sizeof(packet->timestamp)); ldns_pkt_set_answerfrom(packet, NULL); ldns_pkt_set_section_count(packet, LDNS_SECTION_QUESTION, 0); ldns_pkt_set_section_count(packet, LDNS_SECTION_ANSWER, 0); ldns_pkt_set_section_count(packet, LDNS_SECTION_AUTHORITY, 0); ldns_pkt_set_section_count(packet, LDNS_SECTION_ADDITIONAL, 0); ldns_pkt_set_edns_udp_size(packet, 0); ldns_pkt_set_edns_extended_rcode(packet, 0); ldns_pkt_set_edns_version(packet, 0); ldns_pkt_set_edns_z(packet, 0); ldns_pkt_set_edns_data(packet, NULL); packet->_edns_present = false; ldns_pkt_set_tsig(packet, NULL); return packet; } void ldns_pkt_free(ldns_pkt *packet) { if (packet) { LDNS_FREE(packet->_header); ldns_rr_list_deep_free(packet->_question); ldns_rr_list_deep_free(packet->_answer); ldns_rr_list_deep_free(packet->_authority); ldns_rr_list_deep_free(packet->_additional); ldns_rr_free(packet->_tsig_rr); ldns_rdf_deep_free(packet->_edns_data); ldns_rdf_deep_free(packet->_answerfrom); LDNS_FREE(packet); } } bool ldns_pkt_set_flags(ldns_pkt *packet, uint16_t flags) { if (!packet) { return false; } if ((flags & LDNS_QR) == LDNS_QR) { ldns_pkt_set_qr(packet, true); } if ((flags & LDNS_AA) == LDNS_AA) { ldns_pkt_set_aa(packet, true); } if ((flags & LDNS_RD) == LDNS_RD) { ldns_pkt_set_rd(packet, true); } if ((flags & LDNS_TC) == LDNS_TC) { ldns_pkt_set_tc(packet, true); } if ((flags & LDNS_CD) == LDNS_CD) { ldns_pkt_set_cd(packet, true); } if ((flags & LDNS_RA) == LDNS_RA) { ldns_pkt_set_ra(packet, true); } if ((flags & LDNS_AD) == LDNS_AD) { ldns_pkt_set_ad(packet, true); } return true; } static ldns_rr* ldns_pkt_authsoa(ldns_rdf* rr_name, ldns_rr_class rr_class) { ldns_rr* soa_rr = ldns_rr_new(); ldns_rdf *owner_rdf; ldns_rdf *mname_rdf; ldns_rdf *rname_rdf; ldns_rdf *serial_rdf; ldns_rdf *refresh_rdf; ldns_rdf *retry_rdf; ldns_rdf *expire_rdf; ldns_rdf *minimum_rdf; if (!soa_rr) { return NULL; } owner_rdf = ldns_rdf_clone(rr_name); if (!owner_rdf) { ldns_rr_free(soa_rr); return NULL; } ldns_rr_set_owner(soa_rr, owner_rdf); ldns_rr_set_type(soa_rr, LDNS_RR_TYPE_SOA); ldns_rr_set_class(soa_rr, rr_class); ldns_rr_set_question(soa_rr, false); if (ldns_str2rdf_dname(&mname_rdf, ".") != LDNS_STATUS_OK) { ldns_rr_free(soa_rr); return NULL; } else { ldns_rr_push_rdf(soa_rr, mname_rdf); } if (ldns_str2rdf_dname(&rname_rdf, ".") != LDNS_STATUS_OK) { ldns_rr_free(soa_rr); return NULL; } else { ldns_rr_push_rdf(soa_rr, rname_rdf); } serial_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!serial_rdf) { ldns_rr_free(soa_rr); return NULL; } else { ldns_rr_push_rdf(soa_rr, serial_rdf); } refresh_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!refresh_rdf) { ldns_rr_free(soa_rr); return NULL; } else { ldns_rr_push_rdf(soa_rr, refresh_rdf); } retry_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!retry_rdf) { ldns_rr_free(soa_rr); return NULL; } else { ldns_rr_push_rdf(soa_rr, retry_rdf); } expire_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!expire_rdf) { ldns_rr_free(soa_rr); return NULL; } else { ldns_rr_push_rdf(soa_rr, expire_rdf); } minimum_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!minimum_rdf) { ldns_rr_free(soa_rr); return NULL; } else { ldns_rr_push_rdf(soa_rr, minimum_rdf); } return soa_rr; } static ldns_status ldns_pkt_query_new_frm_str_internal(ldns_pkt **p, const char *name, ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags, ldns_rr* authsoa_rr) { ldns_pkt *packet; ldns_rr *question_rr; ldns_rdf *name_rdf; packet = ldns_pkt_new(); if (!packet) { return LDNS_STATUS_MEM_ERR; } if (!ldns_pkt_set_flags(packet, flags)) { return LDNS_STATUS_ERR; } question_rr = ldns_rr_new(); if (!question_rr) { return LDNS_STATUS_MEM_ERR; } if (rr_type == 0) { rr_type = LDNS_RR_TYPE_A; } if (rr_class == 0) { rr_class = LDNS_RR_CLASS_IN; } if (ldns_str2rdf_dname(&name_rdf, name) == LDNS_STATUS_OK) { ldns_rr_set_owner(question_rr, name_rdf); ldns_rr_set_type(question_rr, rr_type); ldns_rr_set_class(question_rr, rr_class); ldns_rr_set_question(question_rr, true); ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr); } else { ldns_rr_free(question_rr); ldns_pkt_free(packet); return LDNS_STATUS_ERR; } if (authsoa_rr) { ldns_pkt_push_rr(packet, LDNS_SECTION_AUTHORITY, authsoa_rr); } packet->_tsig_rr = NULL; ldns_pkt_set_answerfrom(packet, NULL); if (p) { *p = packet; return LDNS_STATUS_OK; } else { ldns_pkt_free(packet); return LDNS_STATUS_NULL; } } ldns_status ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name, ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags) { return ldns_pkt_query_new_frm_str_internal(p, name, rr_type, rr_class, flags, NULL); } ldns_status ldns_pkt_ixfr_request_new_frm_str(ldns_pkt **p, const char *name, ldns_rr_class rr_class, uint16_t flags, ldns_rr *soa) { ldns_rr* authsoa_rr = soa; if (!authsoa_rr) { ldns_rdf *name_rdf; if (ldns_str2rdf_dname(&name_rdf, name) == LDNS_STATUS_OK) { authsoa_rr = ldns_pkt_authsoa(name_rdf, rr_class); } ldns_rdf_free(name_rdf); } return ldns_pkt_query_new_frm_str_internal(p, name, LDNS_RR_TYPE_IXFR, rr_class, flags, authsoa_rr); } static ldns_pkt * ldns_pkt_query_new_internal(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags, ldns_rr* authsoa_rr) { ldns_pkt *packet; ldns_rr *question_rr; packet = ldns_pkt_new(); if (!packet) { return NULL; } if (!ldns_pkt_set_flags(packet, flags)) { return NULL; } question_rr = ldns_rr_new(); if (!question_rr) { ldns_pkt_free(packet); return NULL; } if (rr_type == 0) { rr_type = LDNS_RR_TYPE_A; } if (rr_class == 0) { rr_class = LDNS_RR_CLASS_IN; } ldns_rr_set_owner(question_rr, rr_name); ldns_rr_set_type(question_rr, rr_type); ldns_rr_set_class(question_rr, rr_class); ldns_rr_set_question(question_rr, true); ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr); if (authsoa_rr) { ldns_pkt_push_rr(packet, LDNS_SECTION_AUTHORITY, authsoa_rr); } packet->_tsig_rr = NULL; return packet; } ldns_pkt * ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags) { return ldns_pkt_query_new_internal(rr_name, rr_type, rr_class, flags, NULL); } ldns_pkt * ldns_pkt_ixfr_request_new(ldns_rdf *rr_name, ldns_rr_class rr_class, uint16_t flags, ldns_rr* soa) { ldns_rr* authsoa_rr = soa; if (!authsoa_rr) { authsoa_rr = ldns_pkt_authsoa(rr_name, rr_class); } return ldns_pkt_query_new_internal(rr_name, LDNS_RR_TYPE_IXFR, rr_class, flags, authsoa_rr); } ldns_pkt_type ldns_pkt_reply_type(ldns_pkt *p) { ldns_rr_list *tmp; if (!p) { return LDNS_PACKET_UNKNOWN; } if (ldns_pkt_get_rcode(p) == LDNS_RCODE_NXDOMAIN) { return LDNS_PACKET_NXDOMAIN; } if (ldns_pkt_ancount(p) == 0 && ldns_pkt_arcount(p) == 0 && ldns_pkt_nscount(p) == 1) { /* check for SOA */ tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_SOA, LDNS_SECTION_AUTHORITY); if (tmp) { ldns_rr_list_deep_free(tmp); return LDNS_PACKET_NODATA; } else { /* I have no idea ... */ } } if (ldns_pkt_ancount(p) == 0 && ldns_pkt_nscount(p) > 0) { tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY); if (tmp) { /* there are nameservers here */ ldns_rr_list_deep_free(tmp); return LDNS_PACKET_REFERRAL; } else { /* I have no idea */ } ldns_rr_list_deep_free(tmp); } /* if we cannot determine the packet type, we say it's an * answer... */ return LDNS_PACKET_ANSWER; } ldns_pkt * ldns_pkt_clone(const ldns_pkt *pkt) { ldns_pkt *new_pkt; if (!pkt) { return NULL; } new_pkt = ldns_pkt_new(); ldns_pkt_set_id(new_pkt, ldns_pkt_id(pkt)); ldns_pkt_set_qr(new_pkt, ldns_pkt_qr(pkt)); ldns_pkt_set_aa(new_pkt, ldns_pkt_aa(pkt)); ldns_pkt_set_tc(new_pkt, ldns_pkt_tc(pkt)); ldns_pkt_set_rd(new_pkt, ldns_pkt_rd(pkt)); ldns_pkt_set_cd(new_pkt, ldns_pkt_cd(pkt)); ldns_pkt_set_ra(new_pkt, ldns_pkt_ra(pkt)); ldns_pkt_set_ad(new_pkt, ldns_pkt_ad(pkt)); ldns_pkt_set_opcode(new_pkt, ldns_pkt_get_opcode(pkt)); ldns_pkt_set_rcode(new_pkt, ldns_pkt_get_rcode(pkt)); ldns_pkt_set_qdcount(new_pkt, ldns_pkt_qdcount(pkt)); ldns_pkt_set_ancount(new_pkt, ldns_pkt_ancount(pkt)); ldns_pkt_set_nscount(new_pkt, ldns_pkt_nscount(pkt)); ldns_pkt_set_arcount(new_pkt, ldns_pkt_arcount(pkt)); if (ldns_pkt_answerfrom(pkt)) ldns_pkt_set_answerfrom(new_pkt, ldns_rdf_clone(ldns_pkt_answerfrom(pkt))); ldns_pkt_set_timestamp(new_pkt, ldns_pkt_timestamp(pkt)); ldns_pkt_set_querytime(new_pkt, ldns_pkt_querytime(pkt)); ldns_pkt_set_size(new_pkt, ldns_pkt_size(pkt)); ldns_pkt_set_tsig(new_pkt, ldns_rr_clone(ldns_pkt_tsig(pkt))); ldns_pkt_set_edns_udp_size(new_pkt, ldns_pkt_edns_udp_size(pkt)); ldns_pkt_set_edns_extended_rcode(new_pkt, ldns_pkt_edns_extended_rcode(pkt)); ldns_pkt_set_edns_version(new_pkt, ldns_pkt_edns_version(pkt)); new_pkt->_edns_present = pkt->_edns_present; ldns_pkt_set_edns_z(new_pkt, ldns_pkt_edns_z(pkt)); if(ldns_pkt_edns_data(pkt)) ldns_pkt_set_edns_data(new_pkt, ldns_rdf_clone(ldns_pkt_edns_data(pkt))); ldns_pkt_set_edns_do(new_pkt, ldns_pkt_edns_do(pkt)); ldns_rr_list_deep_free(new_pkt->_question); ldns_rr_list_deep_free(new_pkt->_answer); ldns_rr_list_deep_free(new_pkt->_authority); ldns_rr_list_deep_free(new_pkt->_additional); new_pkt->_question = ldns_rr_list_clone(ldns_pkt_question(pkt)); new_pkt->_answer = ldns_rr_list_clone(ldns_pkt_answer(pkt)); new_pkt->_authority = ldns_rr_list_clone(ldns_pkt_authority(pkt)); new_pkt->_additional = ldns_rr_list_clone(ldns_pkt_additional(pkt)); return new_pkt; } Net-LDNS-0.75/src/ldns/parse.c000644 000770 000024 00000021127 12471046240 016324 0ustar00calledstaff000000 000000 /* * a generic (simple) parser. Use to parse rr's, private key * information and /etc/resolv.conf files * * a Net::DNS like library for C * LibDNS Team @ NLnet Labs * (c) NLnet Labs, 2005-2006 * See the file LICENSE for the license */ #include #include #include #include ldns_lookup_table ldns_directive_types[] = { { LDNS_DIR_TTL, "$TTL" }, { LDNS_DIR_ORIGIN, "$ORIGIN" }, { LDNS_DIR_INCLUDE, "$INCLUDE" }, { 0, NULL } }; /* add max_limit here? */ ssize_t ldns_fget_token(FILE *f, char *token, const char *delim, size_t limit) { return ldns_fget_token_l(f, token, delim, limit, NULL); } ssize_t ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr) { int c, prev_c; int p; /* 0 -> no parenthese seen, >0 nr of ( seen */ int com, quoted; char *t; size_t i; const char *d; const char *del; /* standard delimeters */ if (!delim) { /* from isspace(3) */ del = LDNS_PARSE_NORMAL; } else { del = delim; } p = 0; i = 0; com = 0; quoted = 0; prev_c = 0; t = token; if (del[0] == '"') { quoted = 1; } while ((c = getc(f)) != EOF) { if (c == '\r') /* carriage return */ c = ' '; if (c == '(' && prev_c != '\\' && !quoted) { /* this only counts for non-comments */ if (com == 0) { p++; } prev_c = c; continue; } if (c == ')' && prev_c != '\\' && !quoted) { /* this only counts for non-comments */ if (com == 0) { p--; } prev_c = c; continue; } if (p < 0) { /* more ) then ( - close off the string */ *t = '\0'; return 0; } /* do something with comments ; */ if (c == ';' && quoted == 0) { if (prev_c != '\\') { com = 1; } } if (c == '\"' && com == 0 && prev_c != '\\') { quoted = 1 - quoted; } if (c == '\n' && com != 0) { /* comments */ com = 0; *t = ' '; if (line_nr) { *line_nr = *line_nr + 1; } if (p == 0 && i > 0) { goto tokenread; } else { prev_c = c; continue; } } if (com == 1) { *t = ' '; prev_c = c; continue; } if (c == '\n' && p != 0 && t > token) { /* in parentheses */ if (line_nr) { *line_nr = *line_nr + 1; } *t++ = ' '; prev_c = c; continue; } /* check if we hit the delim */ for (d = del; *d; d++) { if (c == *d && i > 0 && prev_c != '\\' && p == 0) { if (c == '\n' && line_nr) { *line_nr = *line_nr + 1; } goto tokenread; } } if (c != '\0' && c != '\n') { i++; } if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { *t = '\0'; return -1; } if (c != '\0' && c != '\n') { *t++ = c; } if (c == '\\' && prev_c == '\\') prev_c = 0; else prev_c = c; } *t = '\0'; if (c == EOF) { return (ssize_t)i; } if (i == 0) { /* nothing read */ return -1; } if (p != 0) { return -1; } return (ssize_t)i; tokenread: if(*del == '"') /* do not skip over quotes, they are significant */ ldns_fskipcs_l(f, del+1, line_nr); else ldns_fskipcs_l(f, del, line_nr); *t = '\0'; if (p != 0) { return -1; } return (ssize_t)i; } ssize_t ldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit) { return ldns_fget_keyword_data_l(f, keyword, k_del, data, d_del, data_limit, NULL); } ssize_t ldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit, int *line_nr) { /* we assume: keyword|sep|data */ char *fkeyword; ssize_t i; if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN) return -1; fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN); if(!fkeyword) return -1; i = ldns_fget_token(f, fkeyword, k_del, LDNS_MAX_KEYWORDLEN); if(i==0 || i==-1) { LDNS_FREE(fkeyword); return -1; } /* case??? i instead of strlen? */ if (strncmp(fkeyword, keyword, LDNS_MAX_KEYWORDLEN - 1) == 0) { /* whee! */ /* printf("%s\n%s\n", "Matching keyword", fkeyword); */ i = ldns_fget_token_l(f, data, d_del, data_limit, line_nr); LDNS_FREE(fkeyword); return i; } else { /*printf("no match for %s (read: %s)\n", keyword, fkeyword);*/ LDNS_FREE(fkeyword); return -1; } } ssize_t ldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t limit) { int c, lc; int p; /* 0 -> no parenthese seen, >0 nr of ( seen */ int com, quoted; char *t; size_t i; const char *d; const char *del; /* standard delimiters */ if (!delim) { /* from isspace(3) */ del = LDNS_PARSE_NORMAL; } else { del = delim; } p = 0; i = 0; com = 0; quoted = 0; t = token; lc = 0; if (del[0] == '"') { quoted = 1; } while ((c = ldns_bgetc(b)) != EOF) { if (c == '\r') /* carriage return */ c = ' '; if (c == '(' && lc != '\\' && !quoted) { /* this only counts for non-comments */ if (com == 0) { p++; } lc = c; continue; } if (c == ')' && lc != '\\' && !quoted) { /* this only counts for non-comments */ if (com == 0) { p--; } lc = c; continue; } if (p < 0) { /* more ) then ( */ *t = '\0'; return 0; } /* do something with comments ; */ if (c == ';' && quoted == 0) { if (lc != '\\') { com = 1; } } if (c == '"' && com == 0 && lc != '\\') { quoted = 1 - quoted; } if (c == '\n' && com != 0) { /* comments */ com = 0; *t = ' '; lc = c; continue; } if (com == 1) { *t = ' '; lc = c; continue; } if (c == '\n' && p != 0) { /* in parentheses */ *t++ = ' '; lc = c; continue; } /* check if we hit the delim */ for (d = del; *d; d++) { if (c == *d && lc != '\\' && p == 0) { goto tokenread; } } i++; if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { *t = '\0'; return -1; } *t++ = c; if (c == '\\' && lc == '\\') { lc = 0; } else { lc = c; } } *t = '\0'; if (i == 0) { /* nothing read */ return -1; } if (p != 0) { return -1; } return (ssize_t)i; tokenread: if(*del == '"') /* do not skip over quotes, they are significant */ ldns_bskipcs(b, del+1); else ldns_bskipcs(b, del); *t = '\0'; if (p != 0) { return -1; } return (ssize_t)i; } void ldns_bskipcs(ldns_buffer *buffer, const char *s) { bool found; char c; const char *d; while(ldns_buffer_available_at(buffer, buffer->_position, sizeof(char))) { c = (char) ldns_buffer_read_u8_at(buffer, buffer->_position); found = false; for (d = s; *d; d++) { if (*d == c) { found = true; } } if (found && buffer->_limit > buffer->_position) { buffer->_position += sizeof(char); } else { return; } } } void ldns_fskipcs(FILE *fp, const char *s) { ldns_fskipcs_l(fp, s, NULL); } void ldns_fskipcs_l(FILE *fp, const char *s, int *line_nr) { bool found; int c; const char *d; while ((c = fgetc(fp)) != EOF) { if (line_nr && c == '\n') { *line_nr = *line_nr + 1; } found = false; for (d = s; *d; d++) { if (*d == c) { found = true; } } if (!found) { /* with getc, we've read too far */ ungetc(c, fp); return; } } } ssize_t ldns_bget_keyword_data(ldns_buffer *b, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit) { /* we assume: keyword|sep|data */ char *fkeyword; ssize_t i; if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN) return -1; fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN); if(!fkeyword) return -1; /* out of memory */ i = ldns_bget_token(b, fkeyword, k_del, data_limit); if(i==0 || i==-1) { LDNS_FREE(fkeyword); return -1; /* nothing read */ } /* case??? */ if (strncmp(fkeyword, keyword, strlen(keyword)) == 0) { LDNS_FREE(fkeyword); /* whee, the match! */ /* retrieve it's data */ i = ldns_bget_token(b, data, d_del, 0); return i; } else { LDNS_FREE(fkeyword); return -1; } } Net-LDNS-0.75/src/ldns/radix.c000644 000770 000024 00000110776 12471046240 016332 0ustar00calledstaff000000 000000 /* * radix.c -- generic radix tree * * Taken from NSD4, modified for ldns * * Copyright (c) 2012, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * \file * Implementation of a radix tree. */ #include #include #include #include /** Helper functions */ static ldns_radix_node_t* ldns_radix_new_node(void* data, uint8_t* key, radix_strlen_t len); static int ldns_radix_find_prefix(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len, ldns_radix_node_t** result, radix_strlen_t* pos); static int ldns_radix_array_space(ldns_radix_node_t* node, uint8_t byte); static int ldns_radix_array_grow(ldns_radix_node_t* node, unsigned need); static int ldns_radix_str_create(ldns_radix_array_t* array, uint8_t* key, radix_strlen_t pos, radix_strlen_t len); static int ldns_radix_prefix_remainder(radix_strlen_t prefix_len, uint8_t* longer_str, radix_strlen_t longer_len, uint8_t** split_str, radix_strlen_t* split_len); static int ldns_radix_array_split(ldns_radix_array_t* array, uint8_t* key, radix_strlen_t pos, radix_strlen_t len, ldns_radix_node_t* add); static int ldns_radix_str_is_prefix(uint8_t* str1, radix_strlen_t len1, uint8_t* str2, radix_strlen_t len2); static radix_strlen_t ldns_radix_str_common(uint8_t* str1, radix_strlen_t len1, uint8_t* str2, radix_strlen_t len2); static ldns_radix_node_t* ldns_radix_next_in_subtree(ldns_radix_node_t* node); static ldns_radix_node_t* ldns_radix_prev_from_index(ldns_radix_node_t* node, uint8_t index); static ldns_radix_node_t* ldns_radix_last_in_subtree_incl_self( ldns_radix_node_t* node); static ldns_radix_node_t* ldns_radix_last_in_subtree(ldns_radix_node_t* node); static void ldns_radix_del_fix(ldns_radix_t* tree, ldns_radix_node_t* node); static void ldns_radix_cleanup_onechild(ldns_radix_node_t* node); static void ldns_radix_cleanup_leaf(ldns_radix_node_t* node); static void ldns_radix_node_free(ldns_radix_node_t* node, void* arg); static void ldns_radix_node_array_free(ldns_radix_node_t* node); static void ldns_radix_node_array_free_front(ldns_radix_node_t* node); static void ldns_radix_node_array_free_end(ldns_radix_node_t* node); static void ldns_radix_array_reduce(ldns_radix_node_t* node); static void ldns_radix_self_or_prev(ldns_radix_node_t* node, ldns_radix_node_t** result); /** * Create a new radix node. * */ static ldns_radix_node_t* ldns_radix_new_node(void* data, uint8_t* key, radix_strlen_t len) { ldns_radix_node_t* node = LDNS_MALLOC(ldns_radix_node_t); if (!node) { return NULL; } node->data = data; node->key = key; node->klen = len; node->parent = NULL; node->parent_index = 0; node->len = 0; node->offset = 0; node->capacity = 0; node->array = NULL; return node; } /** * Create a new radix tree. * */ ldns_radix_t * ldns_radix_create(void) { ldns_radix_t* tree; /** Allocate memory for it */ tree = (ldns_radix_t *) LDNS_MALLOC(ldns_radix_t); if (!tree) { return NULL; } /** Initialize it */ ldns_radix_init(tree); return tree; } /** * Initialize radix tree. * */ void ldns_radix_init(ldns_radix_t* tree) { /** Initialize it */ if (tree) { tree->root = NULL; tree->count = 0; } return; } /** * Free radix tree. * */ void ldns_radix_free(ldns_radix_t* tree) { if (tree) { if (tree->root) { ldns_radix_traverse_postorder(tree->root, ldns_radix_node_free, NULL); } LDNS_FREE(tree); } return; } /** * Insert data into the tree. * */ ldns_status ldns_radix_insert(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len, void* data) { radix_strlen_t pos = 0; ldns_radix_node_t* add = NULL; ldns_radix_node_t* prefix = NULL; if (!tree || !key || !data) { return LDNS_STATUS_NULL; } add = ldns_radix_new_node(data, key, len); if (!add) { return LDNS_STATUS_MEM_ERR; } /** Search the trie until we can make no further process. */ if (!ldns_radix_find_prefix(tree, key, len, &prefix, &pos)) { /** No prefix found */ assert(tree->root == NULL); if (len == 0) { /** * Example 1: The root: * | [0] **/ tree->root = add; } else { /** Example 2: 'dns': * | [0] * --| [d+ns] dns **/ prefix = ldns_radix_new_node(NULL, (uint8_t*)"", 0); if (!prefix) { LDNS_FREE(add); return LDNS_STATUS_MEM_ERR; } /** Find some space in the array for the first byte */ if (!ldns_radix_array_space(prefix, key[0])) { LDNS_FREE(add); LDNS_FREE(prefix->array); LDNS_FREE(prefix); return LDNS_STATUS_MEM_ERR; } /** Set relational pointers */ add->parent = prefix; add->parent_index = 0; prefix->array[0].edge = add; if (len > 1) { /** Store the remainder of the prefix */ if (!ldns_radix_prefix_remainder(1, key, len, &prefix->array[0].str, &prefix->array[0].len)) { LDNS_FREE(add); LDNS_FREE(prefix->array); LDNS_FREE(prefix); return LDNS_STATUS_MEM_ERR; } } tree->root = prefix; } } else if (pos == len) { /** Exact match found */ if (prefix->data) { /* Element already exists */ LDNS_FREE(add); return LDNS_STATUS_EXISTS_ERR; } prefix->data = data; prefix->key = key; prefix->klen = len; /* redundant */ } else { /** Prefix found */ uint8_t byte = key[pos]; assert(pos < len); if (byte < prefix->offset || (byte - prefix->offset) >= prefix->len) { /** Find some space in the array for the byte. */ /** * Example 3: 'ldns' * | [0] * --| [d+ns] dns * --| [l+dns] ldns **/ if (!ldns_radix_array_space(prefix, byte)) { LDNS_FREE(add); return LDNS_STATUS_MEM_ERR; } assert(byte >= prefix->offset); assert((byte - prefix->offset) <= prefix->len); byte -= prefix->offset; if (pos+1 < len) { /** Create remainder of the string. */ if (!ldns_radix_str_create( &prefix->array[byte], key, pos+1, len)) { LDNS_FREE(add); return LDNS_STATUS_MEM_ERR; } } /** Add new node. */ add->parent = prefix; add->parent_index = byte; prefix->array[byte].edge = add; } else if (prefix->array[byte-prefix->offset].edge == NULL) { /** Use existing element. */ /** * Example 4: 'edns' * | [0] * --| [d+ns] dns * --| [e+dns] edns * --| [l+dns] ldns **/ byte -= prefix->offset; if (pos+1 < len) { /** Create remainder of the string. */ if (!ldns_radix_str_create( &prefix->array[byte], key, pos+1, len)) { LDNS_FREE(add); return LDNS_STATUS_MEM_ERR; } } /** Add new node. */ add->parent = prefix; add->parent_index = byte; prefix->array[byte].edge = add; } else { /** * Use existing element, but it has a shared prefix, * we need a split. */ if (!ldns_radix_array_split(&prefix->array[byte-(prefix->offset)], key, pos+1, len, add)) { LDNS_FREE(add); return LDNS_STATUS_MEM_ERR; } } } tree->count ++; return LDNS_STATUS_OK; } /** * Delete data from the tree. * */ void* ldns_radix_delete(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len) { ldns_radix_node_t* del = ldns_radix_search(tree, key, len); void* data = NULL; if (del) { tree->count--; data = del->data; del->data = NULL; ldns_radix_del_fix(tree, del); return data; } return NULL; } /** * Search data in the tree. * */ ldns_radix_node_t* ldns_radix_search(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len) { ldns_radix_node_t* node = NULL; radix_strlen_t pos = 0; uint8_t byte = 0; if (!tree || !key) { return NULL; } node = tree->root; while (node) { if (pos == len) { return node->data?node:NULL; } byte = key[pos]; if (byte < node->offset) { return NULL; } byte -= node->offset; if (byte >= node->len) { return NULL; } pos++; if (node->array[byte].len > 0) { /** Must match additional string. */ if (pos + node->array[byte].len > len) { return NULL; } if (memcmp(&key[pos], node->array[byte].str, node->array[byte].len) != 0) { return NULL; } pos += node->array[byte].len; } node = node->array[byte].edge; } return NULL; } /** * Search data in the tree, and if not found, find the closest smaller * element in the tree. * */ int ldns_radix_find_less_equal(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len, ldns_radix_node_t** result) { ldns_radix_node_t* node = NULL; radix_strlen_t pos = 0; uint8_t byte; int memcmp_res = 0; if (!tree || !tree->root || !key) { *result = NULL; return 0; } node = tree->root; while (pos < len) { byte = key[pos]; if (byte < node->offset) { /** * No exact match. The lesser is in this or the * previous node. */ ldns_radix_self_or_prev(node, result); return 0; } byte -= node->offset; if (byte >= node->len) { /** * No exact match. The lesser is in this node or the * last of this array, or something before this node. */ *result = ldns_radix_last_in_subtree_incl_self(node); if (*result == NULL) { *result = ldns_radix_prev(node); } return 0; } pos++; if (!node->array[byte].edge) { /** * No exact match. Find the previous in the array * from this index. */ *result = ldns_radix_prev_from_index(node, byte); if (*result == NULL) { ldns_radix_self_or_prev(node, result); } return 0; } if (node->array[byte].len != 0) { /** Must match additional string. */ if (pos + node->array[byte].len > len) { /** Additional string is longer than key. */ if (memcmp(&key[pos], node->array[byte].str, len-pos) <= 0) { /** Key is before this node. */ *result = ldns_radix_prev( node->array[byte].edge); } else { /** Key is after additional string. */ *result = ldns_radix_last_in_subtree_incl_self(node->array[byte].edge); if (*result == NULL) { *result = ldns_radix_prev(node->array[byte].edge); } } return 0; } memcmp_res = memcmp(&key[pos], node->array[byte].str, node->array[byte].len); if (memcmp_res < 0) { *result = ldns_radix_prev( node->array[byte].edge); return 0; } else if (memcmp_res > 0) { *result = ldns_radix_last_in_subtree_incl_self(node->array[byte].edge); if (*result == NULL) { *result = ldns_radix_prev(node->array[byte].edge); } return 0; } pos += node->array[byte].len; } node = node->array[byte].edge; } if (node->data) { /** Exact match. */ *result = node; return 1; } /** There is a node which is an exact match, but has no element. */ *result = ldns_radix_prev(node); return 0; } /** * Get the first element in the tree. * */ ldns_radix_node_t* ldns_radix_first(ldns_radix_t* tree) { ldns_radix_node_t* first = NULL; if (!tree || !tree->root) { return NULL; } first = tree->root; if (first->data) { return first; } return ldns_radix_next(first); } /** * Get the last element in the tree. * */ ldns_radix_node_t* ldns_radix_last(ldns_radix_t* tree) { if (!tree || !tree->root) { return NULL; } return ldns_radix_last_in_subtree_incl_self(tree->root); } /** * Next element. * */ ldns_radix_node_t* ldns_radix_next(ldns_radix_node_t* node) { if (!node) { return NULL; } if (node->len) { /** Go down: most-left child is the next. */ ldns_radix_node_t* next = ldns_radix_next_in_subtree(node); if (next) { return next; } } /** No elements in subtree, get to parent and go down next branch. */ while (node->parent) { uint8_t index = node->parent_index; node = node->parent; index++; for (; index < node->len; index++) { if (node->array[index].edge) { ldns_radix_node_t* next; /** Node itself. */ if (node->array[index].edge->data) { return node->array[index].edge; } /** Dive into subtree. */ next = ldns_radix_next_in_subtree(node); if (next) { return next; } } } } return NULL; } /** * Previous element. * */ ldns_radix_node_t* ldns_radix_prev(ldns_radix_node_t* node) { if (!node) { return NULL; } /** Get to parent and go down previous branch. */ while (node->parent) { uint8_t index = node->parent_index; ldns_radix_node_t* prev; node = node->parent; assert(node->len > 0); prev = ldns_radix_prev_from_index(node, index); if (prev) { return prev; } if (node->data) { return node; } } return NULL; } /** * Print node. * */ static void ldns_radix_node_print(FILE* fd, ldns_radix_node_t* node, uint8_t i, uint8_t* str, radix_strlen_t len, unsigned d) { uint8_t j; if (!node) { return; } for (j = 0; j < d; j++) { fprintf(fd, "--"); } if (str) { radix_strlen_t l; fprintf(fd, "| [%u+", (unsigned) i); for (l=0; l < len; l++) { fprintf(fd, "%c", (char) str[l]); } fprintf(fd, "]%u", (unsigned) len); } else { fprintf(fd, "| [%u]", (unsigned) i); } if (node->data) { fprintf(fd, " %s", (char*) node->data); } fprintf(fd, "\n"); for (j = 0; j < node->len; j++) { if (node->array[j].edge) { ldns_radix_node_print(fd, node->array[j].edge, j, node->array[j].str, node->array[j].len, d+1); } } return; } /** * Print radix tree. * */ void ldns_radix_printf(FILE* fd, ldns_radix_t* tree) { if (!fd || !tree) { return; } if (!tree->root) { fprintf(fd, "; empty radix tree\n"); return; } ldns_radix_node_print(fd, tree->root, 0, NULL, 0, 0); return; } /** * Join two radix trees. * */ ldns_status ldns_radix_join(ldns_radix_t* tree1, ldns_radix_t* tree2) { ldns_radix_node_t* cur_node, *next_node; ldns_status status; if (!tree2 || !tree2->root) { return LDNS_STATUS_OK; } /** Add all elements from tree2 into tree1. */ cur_node = ldns_radix_first(tree2); while (cur_node) { status = LDNS_STATUS_NO_DATA; /** Insert current node into tree1 */ if (cur_node->data) { status = ldns_radix_insert(tree1, cur_node->key, cur_node->klen, cur_node->data); /** Exist errors may occur */ if (status != LDNS_STATUS_OK && status != LDNS_STATUS_EXISTS_ERR) { return status; } } next_node = ldns_radix_next(cur_node); if (status == LDNS_STATUS_OK) { (void) ldns_radix_delete(tree2, cur_node->key, cur_node->klen); } cur_node = next_node; } return LDNS_STATUS_OK; } /** * Split a radix tree intwo. * */ ldns_status ldns_radix_split(ldns_radix_t* tree1, size_t num, ldns_radix_t** tree2) { size_t count = 0; ldns_radix_node_t* cur_node; ldns_status status = LDNS_STATUS_OK; if (!tree1 || !tree1->root || num == 0) { return LDNS_STATUS_OK; } if (!tree2) { return LDNS_STATUS_NULL; } if (!*tree2) { *tree2 = ldns_radix_create(); if (!*tree2) { return LDNS_STATUS_MEM_ERR; } } cur_node = ldns_radix_first(tree1); while (count < num && cur_node) { if (cur_node->data) { /** Delete current node from tree1. */ uint8_t* cur_key = cur_node->key; radix_strlen_t cur_len = cur_node->klen; void* cur_data = ldns_radix_delete(tree1, cur_key, cur_len); /** Insert current node into tree2/ */ if (!cur_data) { return LDNS_STATUS_NO_DATA; } status = ldns_radix_insert(*tree2, cur_key, cur_len, cur_data); if (status != LDNS_STATUS_OK && status != LDNS_STATUS_EXISTS_ERR) { return status; } /* if (status == LDNS_STATUS_OK) { cur_node->key = NULL; cur_node->klen = 0; } */ /** Update count; get first element from tree1 again. */ count++; cur_node = ldns_radix_first(tree1); } else { cur_node = ldns_radix_next(cur_node); } } return LDNS_STATUS_OK; } /** * Call function for all nodes in the tree, such that leaf nodes are * called before parent nodes. * */ void ldns_radix_traverse_postorder(ldns_radix_node_t* node, void (*func)(ldns_radix_node_t*, void*), void* arg) { uint8_t i; if (!node) { return; } for (i=0; i < node->len; i++) { ldns_radix_traverse_postorder(node->array[i].edge, func, arg); } /** Call user function */ (*func)(node, arg); return; } /** Static helper functions */ /** * Find a prefix of the key. * @param tree: tree. * @param key: key. * @param len: length of key. * @param result: the longest prefix, the entry itself if *pos==len, * otherwise an array entry. * @param pos: position in string where next unmatched byte is. * If *pos==len, an exact match is found. * If *pos== 0, a "" match was found. * @return 0 (false) if no prefix found. * */ static int ldns_radix_find_prefix(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len, ldns_radix_node_t** result, radix_strlen_t* respos) { /** Start searching at the root node */ ldns_radix_node_t* n = tree->root; radix_strlen_t pos = 0; uint8_t byte; *respos = 0; *result = n; if (!n) { /** No root, no prefix found */ return 0; } /** For each node, look if we can make further progress */ while (n) { if (pos == len) { /** Exact match */ return 1; } byte = key[pos]; if (byte < n->offset) { /** key < node */ return 1; } byte -= n->offset; if (byte >= n->len) { /** key > node */ return 1; } /** So far, the trie matches */ pos++; if (n->array[byte].len != 0) { /** Must match additional string */ if (pos + n->array[byte].len > len) { return 1; /* no match at child node */ } if (memcmp(&key[pos], n->array[byte].str, n->array[byte].len) != 0) { return 1; /* no match at child node */ } pos += n->array[byte].len; } /** Continue searching prefix at this child node */ n = n->array[byte].edge; if (!n) { return 1; } /** Update the prefix node */ *respos = pos; *result = n; } /** Done */ return 1; } /** * Make space in the node's array for another byte. * @param node: node. * @param byte: byte. * @return 1 if successful, 0 otherwise. * */ static int ldns_radix_array_space(ldns_radix_node_t* node, uint8_t byte) { /** Is there an array? */ if (!node->array) { assert(node->capacity == 0); /** No array, create new array */ node->array = LDNS_MALLOC(ldns_radix_array_t); if (!node->array) { return 0; } memset(&node->array[0], 0, sizeof(ldns_radix_array_t)); node->len = 1; node->capacity = 1; node->offset = byte; return 1; } /** Array exist */ assert(node->array != NULL); assert(node->capacity > 0); if (node->len == 0) { /** Unused array */ node->len = 1; node->offset = byte; } else if (byte < node->offset) { /** Byte is below the offset */ uint8_t index; uint16_t need = node->offset - byte; /** Is there enough capacity? */ if (node->len + need > node->capacity) { /** Not enough capacity, grow array */ if (!ldns_radix_array_grow(node, (unsigned) (node->len + need))) { return 0; /* failed to grow array */ } } /** Move items to the end */ memmove(&node->array[need], &node->array[0], node->len*sizeof(ldns_radix_array_t)); /** Fix parent index */ for (index = 0; index < node->len; index++) { if (node->array[index+need].edge) { node->array[index+need].edge->parent_index = index + need; } } /** Zero the first */ memset(&node->array[0], 0, need*sizeof(ldns_radix_array_t)); node->len += need; node->offset = byte; } else if (byte - node->offset >= node->len) { /** Byte does not fit in array */ uint16_t need = (byte - node->offset) - node->len + 1; /** Is there enough capacity? */ if (node->len + need > node->capacity) { /** Not enough capacity, grow array */ if (!ldns_radix_array_grow(node, (unsigned) (node->len + need))) { return 0; /* failed to grow array */ } } /** Zero the added items */ memset(&node->array[node->len], 0, need*sizeof(ldns_radix_array_t)); node->len += need; } return 1; } /** * Grow the array. * @param node: node. * @param need: number of elements the array at least need to grow. * Can't be bigger than 256. * @return: 0 if failed, 1 if was successful. * */ static int ldns_radix_array_grow(ldns_radix_node_t* node, unsigned need) { unsigned size = ((unsigned)node->capacity)*2; ldns_radix_array_t* a = NULL; if (need > size) { size = need; } if (size > 256) { size = 256; } a = LDNS_XMALLOC(ldns_radix_array_t, size); if (!a) { return 0; } assert(node->len <= node->capacity); assert(node->capacity < size); memcpy(&a[0], &node->array[0], node->len*sizeof(ldns_radix_array_t)); LDNS_FREE(node->array); node->array = a; node->capacity = size; return 1; } /** * Create a prefix in the array string. * @param array: array. * @param key: key. * @param pos: start position in key. * @param len: length of key. * @return 0 if failed, 1 if was successful. * */ static int ldns_radix_str_create(ldns_radix_array_t* array, uint8_t* key, radix_strlen_t pos, radix_strlen_t len) { array->str = LDNS_XMALLOC(uint8_t, (len-pos)); if (!array->str) { return 0; } memmove(array->str, key+pos, len-pos); array->len = (len-pos); return 1; } /** * Allocate remainder from prefixes for a split. * @param prefixlen: length of prefix. * @param longer_str: the longer string. * @param longer_len: the longer string length. * @param split_str: the split string. * @param split_len: the split string length. * @return 0 if failed, 1 if successful. * */ static int ldns_radix_prefix_remainder(radix_strlen_t prefix_len, uint8_t* longer_str, radix_strlen_t longer_len, uint8_t** split_str, radix_strlen_t* split_len) { *split_len = longer_len - prefix_len; *split_str = LDNS_XMALLOC(uint8_t, (*split_len)); if (!*split_str) { return 0; } memmove(*split_str, longer_str+prefix_len, longer_len-prefix_len); return 1; } /** * Create a split when two nodes have a shared prefix. * @param array: array. * @param key: key. * @param pos: start position in key. * @param len: length of the key. * @param add: node to be added. * @return 0 if failed, 1 if was successful. * */ static int ldns_radix_array_split(ldns_radix_array_t* array, uint8_t* key, radix_strlen_t pos, radix_strlen_t len, ldns_radix_node_t* add) { uint8_t* str_to_add = key + pos; radix_strlen_t strlen_to_add = len - pos; if (ldns_radix_str_is_prefix(str_to_add, strlen_to_add, array->str, array->len)) { /** The string to add is a prefix of the existing string */ uint8_t* split_str = NULL, *dup_str = NULL; radix_strlen_t split_len = 0; /** * Example 5: 'ld' * | [0] * --| [d+ns] dns * --| [e+dns] edns * --| [l+d] ld * ----| [n+s] ldns **/ assert(strlen_to_add < array->len); /** Store the remainder in the split string */ if (array->len - strlen_to_add > 1) { if (!ldns_radix_prefix_remainder(strlen_to_add+1, array->str, array->len, &split_str, &split_len)) { return 0; } } /** Duplicate the string to add */ if (strlen_to_add != 0) { dup_str = LDNS_XMALLOC(uint8_t, strlen_to_add); if (!dup_str) { LDNS_FREE(split_str); return 0; } memcpy(dup_str, str_to_add, strlen_to_add); } /** Make space in array for the new node */ if (!ldns_radix_array_space(add, array->str[strlen_to_add])) { LDNS_FREE(split_str); LDNS_FREE(dup_str); return 0; } /** * The added node should go direct under the existing parent. * The existing node should go under the added node. */ add->parent = array->edge->parent; add->parent_index = array->edge->parent_index; add->array[0].edge = array->edge; add->array[0].str = split_str; add->array[0].len = split_len; array->edge->parent = add; array->edge->parent_index = 0; LDNS_FREE(array->str); array->edge = add; array->str = dup_str; array->len = strlen_to_add; } else if (ldns_radix_str_is_prefix(array->str, array->len, str_to_add, strlen_to_add)) { /** The existing string is a prefix of the string to add */ /** * Example 6: 'dns-ng' * | [0] * --| [d+ns] dns * ----| [-+ng] dns-ng * --| [e+dns] edns * --| [l+d] ld * ----| [n+s] ldns **/ uint8_t* split_str = NULL; radix_strlen_t split_len = 0; assert(array->len < strlen_to_add); if (strlen_to_add - array->len > 1) { if (!ldns_radix_prefix_remainder(array->len+1, str_to_add, strlen_to_add, &split_str, &split_len)) { return 0; } } /** Make space in array for the new node */ if (!ldns_radix_array_space(array->edge, str_to_add[array->len])) { LDNS_FREE(split_str); return 0; } /** * The added node should go direct under the existing node. */ add->parent = array->edge; add->parent_index = str_to_add[array->len] - array->edge->offset; array->edge->array[add->parent_index].edge = add; array->edge->array[add->parent_index].str = split_str; array->edge->array[add->parent_index].len = split_len; } else { /** Create a new split node. */ /** * Example 7: 'dndns' * | [0] * --| [d+n] * ----| [d+ns] dndns * ----| [s] dns * ------| [-+ng] dns-ng * --| [e+dns] edns * --| [l+d] ld * ----| [n+s] ldns **/ ldns_radix_node_t* common = NULL; uint8_t* common_str = NULL, *s1 = NULL, *s2 = NULL; radix_strlen_t common_len = 0, l1 = 0, l2 = 0; common_len = ldns_radix_str_common(array->str, array->len, str_to_add, strlen_to_add); assert(common_len < array->len); assert(common_len < strlen_to_add); /** Create the new common node. */ common = ldns_radix_new_node(NULL, (uint8_t*)"", 0); if (!common) { return 0; } if (array->len - common_len > 1) { if (!ldns_radix_prefix_remainder(common_len+1, array->str, array->len, &s1, &l1)) { return 0; } } if (strlen_to_add - common_len > 1) { if (!ldns_radix_prefix_remainder(common_len+1, str_to_add, strlen_to_add, &s2, &l2)) { return 0; } } /** Create the shared prefix. */ if (common_len > 0) { common_str = LDNS_XMALLOC(uint8_t, common_len); if (!common_str) { LDNS_FREE(common); LDNS_FREE(s1); LDNS_FREE(s2); return 0; } memcpy(common_str, str_to_add, common_len); } /** Make space in the common node array. */ if (!ldns_radix_array_space(common, array->str[common_len]) || !ldns_radix_array_space(common, str_to_add[common_len])) { LDNS_FREE(common->array); LDNS_FREE(common); LDNS_FREE(common_str); LDNS_FREE(s1); LDNS_FREE(s2); return 0; } /** * The common node should go direct under the parent node. * The added and existing nodes go under the common node. */ common->parent = array->edge->parent; common->parent_index = array->edge->parent_index; array->edge->parent = common; array->edge->parent_index = array->str[common_len] - common->offset; add->parent = common; add->parent_index = str_to_add[common_len] - common->offset; common->array[array->edge->parent_index].edge = array->edge; common->array[array->edge->parent_index].str = s1; common->array[array->edge->parent_index].len = l1; common->array[add->parent_index].edge = add; common->array[add->parent_index].str = s2; common->array[add->parent_index].len = l2; LDNS_FREE(array->str); array->edge = common; array->str = common_str; array->len = common_len; } return 1; } /** * Check if one string prefix of other string. * @param str1: one string. * @param len1: one string length. * @param str2: other string. * @param len2: other string length. * @return 1 if prefix, 0 otherwise. * */ static int ldns_radix_str_is_prefix(uint8_t* str1, radix_strlen_t len1, uint8_t* str2, radix_strlen_t len2) { if (len1 == 0) { return 1; /* empty prefix is also a prefix */ } if (len1 > len2) { return 0; /* len1 is longer so str1 cannot be a prefix */ } return (memcmp(str1, str2, len1) == 0); } /** * Return the number of bytes in common for the two strings. * @param str1: one string. * @param len1: one string length. * @param str2: other string. * @param len2: other string length. * @return length of substring that the two strings have in common. * */ static radix_strlen_t ldns_radix_str_common(uint8_t* str1, radix_strlen_t len1, uint8_t* str2, radix_strlen_t len2) { radix_strlen_t i, max = (len1len; i++) { if (node->array[i].edge) { /** Node itself. */ if (node->array[i].edge->data) { return node->array[i].edge; } /** Dive into subtree. */ next = ldns_radix_next_in_subtree(node->array[i].edge); if (next) { return next; } } } return NULL; } /** * Find the previous element in the array of this node, from index. * @param node: node. * @param index: index. * @return previous node from index. * */ static ldns_radix_node_t* ldns_radix_prev_from_index(ldns_radix_node_t* node, uint8_t index) { uint8_t i = index; while (i > 0) { i--; if (node->array[i].edge) { ldns_radix_node_t* prev = ldns_radix_last_in_subtree_incl_self(node); if (prev) { return prev; } } } return NULL; } /** * Find last node in subtree, or this node (if have data). * @param node: node. * @return last node in subtree, or this node, or NULL. * */ static ldns_radix_node_t* ldns_radix_last_in_subtree_incl_self(ldns_radix_node_t* node) { ldns_radix_node_t* last = ldns_radix_last_in_subtree(node); if (last) { return last; } else if (node->data) { return node; } return NULL; } /** * Find last node in subtree. * @param node: node. * @return last node in subtree. * */ static ldns_radix_node_t* ldns_radix_last_in_subtree(ldns_radix_node_t* node) { int i; /** Look for the most right leaf node. */ for (i=(int)(node->len)-1; i >= 0; i--) { if (node->array[i].edge) { /** Keep looking for the most right leaf node. */ if (node->array[i].edge->len > 0) { ldns_radix_node_t* last = ldns_radix_last_in_subtree( node->array[i].edge); if (last) { return last; } } /** Could this be the most right leaf node? */ if (node->array[i].edge->data) { return node->array[i].edge; } } } return NULL; } /** * Fix tree after deleting element. * @param tree: tree. * @param node: node with deleted element. * */ static void ldns_radix_del_fix(ldns_radix_t* tree, ldns_radix_node_t* node) { while (node) { if (node->data) { /** Thou should not delete nodes with data attached. */ return; } else if (node->len == 1 && node->parent) { /** Node with one child is fold back into. */ ldns_radix_cleanup_onechild(node); return; } else if (node->len == 0) { /** Leaf node. */ ldns_radix_node_t* parent = node->parent; if (!parent) { /** The root is a leaf node. */ ldns_radix_node_free(node, NULL); tree->root = NULL; return; } /** Cleanup leaf node and continue with parent. */ ldns_radix_cleanup_leaf(node); node = parent; } else { /** * Node cannot be deleted, because it has edge nodes * and no parent to fix up to. */ return; } } /** Not reached. */ return; } /** * Clean up a node with one child. * @param node: node with one child. * */ static void ldns_radix_cleanup_onechild(ldns_radix_node_t* node) { uint8_t* join_str; radix_strlen_t join_len; uint8_t parent_index = node->parent_index; ldns_radix_node_t* child = node->array[0].edge; ldns_radix_node_t* parent = node->parent; /** Node has one child, merge the child node into the parent node. */ assert(parent_index < parent->len); join_len = parent->array[parent_index].len + node->array[0].len + 1; join_str = LDNS_XMALLOC(uint8_t, join_len); if (!join_str) { /** * Cleanup failed due to out of memory. * This tree is now inefficient, with the empty node still * existing, but it is still valid. */ return; } memcpy(join_str, parent->array[parent_index].str, parent->array[parent_index].len); join_str[parent->array[parent_index].len] = child->parent_index + node->offset; memmove(join_str + parent->array[parent_index].len+1, node->array[0].str, node->array[0].len); LDNS_FREE(parent->array[parent_index].str); parent->array[parent_index].str = join_str; parent->array[parent_index].len = join_len; parent->array[parent_index].edge = child; child->parent = parent; child->parent_index = parent_index; ldns_radix_node_free(node, NULL); return; } /** * Clean up a leaf node. * @param node: leaf node. * */ static void ldns_radix_cleanup_leaf(ldns_radix_node_t* node) { uint8_t parent_index = node->parent_index; ldns_radix_node_t* parent = node->parent; /** Delete lead node and fix parent array. */ assert(parent_index < parent->len); ldns_radix_node_free(node, NULL); LDNS_FREE(parent->array[parent_index].str); parent->array[parent_index].str = NULL; parent->array[parent_index].len = 0; parent->array[parent_index].edge = NULL; /** Fix array in parent. */ if (parent->len == 1) { ldns_radix_node_array_free(parent); } else if (parent_index == 0) { ldns_radix_node_array_free_front(parent); } else { ldns_radix_node_array_free_end(parent); } return; } /** * Free a radix node. * @param node: node. * @param arg: user argument. * */ static void ldns_radix_node_free(ldns_radix_node_t* node, void* arg) { uint16_t i; (void) arg; if (!node) { return; } for (i=0; i < node->len; i++) { LDNS_FREE(node->array[i].str); } node->key = NULL; node->klen = 0; LDNS_FREE(node->array); LDNS_FREE(node); return; } /** * Free select edge array. * @param node: node. * */ static void ldns_radix_node_array_free(ldns_radix_node_t* node) { node->offset = 0; node->len = 0; LDNS_FREE(node->array); node->array = NULL; node->capacity = 0; return; } /** * Free front of select edge array. * @param node: node. * */ static void ldns_radix_node_array_free_front(ldns_radix_node_t* node) { uint16_t i, n = 0; /** Remove until a non NULL entry. */ while (n < node->len && node->array[n].edge == NULL) { n++; } if (n == 0) { return; } if (n == node->len) { ldns_radix_node_array_free(node); return; } assert(n < node->len); assert((int) n <= (255 - (int) node->offset)); memmove(&node->array[0], &node->array[n], (node->len - n)*sizeof(ldns_radix_array_t)); node->offset += n; node->len -= n; for (i=0; i < node->len; i++) { if (node->array[i].edge) { node->array[i].edge->parent_index = i; } } ldns_radix_array_reduce(node); return; } /** * Free front of select edge array. * @param node: node. * */ static void ldns_radix_node_array_free_end(ldns_radix_node_t* node) { uint16_t n = 0; /** Shorten array. */ while (n < node->len && node->array[node->len-1-n].edge == NULL) { n++; } if (n == 0) { return; } if (n == node->len) { ldns_radix_node_array_free(node); return; } assert(n < node->len); node->len -= n; ldns_radix_array_reduce(node); return; } /** * Reduce the capacity of the array if needed. * @param node: node. * */ static void ldns_radix_array_reduce(ldns_radix_node_t* node) { if (node->len <= node->capacity/2 && node->len != node->capacity) { ldns_radix_array_t* a = LDNS_XMALLOC(ldns_radix_array_t, node->len); if (!a) { return; } memcpy(a, node->array, sizeof(ldns_radix_array_t)*node->len); LDNS_FREE(node->array); node->array = a; node->capacity = node->len; } return; } /** * Return this element if it exists, the previous otherwise. * @param node: from this node. * @param result: result node. * */ static void ldns_radix_self_or_prev(ldns_radix_node_t* node, ldns_radix_node_t** result) { if (node->data) { *result = node; } else { *result = ldns_radix_prev(node); } return; } Net-LDNS-0.75/src/ldns/rbtree.c000644 000770 000024 00000042462 12471046240 016502 0ustar00calledstaff000000 000000 /* * rbtree.c -- generic red black tree * * Taken from Unbound, modified for ldns * * Copyright (c) 2001-2008, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * \file * Implementation of a redblack tree. */ #include #include #include #include /** Node colour black */ #define BLACK 0 /** Node colour red */ #define RED 1 /** the NULL node, global alloc */ ldns_rbnode_t ldns_rbtree_null_node = { LDNS_RBTREE_NULL, /* Parent. */ LDNS_RBTREE_NULL, /* Left. */ LDNS_RBTREE_NULL, /* Right. */ NULL, /* Key. */ NULL, /* Data. */ BLACK /* Color. */ }; /** rotate subtree left (to preserve redblack property) */ static void ldns_rbtree_rotate_left(ldns_rbtree_t *rbtree, ldns_rbnode_t *node); /** rotate subtree right (to preserve redblack property) */ static void ldns_rbtree_rotate_right(ldns_rbtree_t *rbtree, ldns_rbnode_t *node); /** Fixup node colours when insert happened */ static void ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node); /** Fixup node colours when delete happened */ static void ldns_rbtree_delete_fixup(ldns_rbtree_t* rbtree, ldns_rbnode_t* child, ldns_rbnode_t* child_parent); /* * Creates a new red black tree, intializes and returns a pointer to it. * * Return NULL on failure. * */ ldns_rbtree_t * ldns_rbtree_create (int (*cmpf)(const void *, const void *)) { ldns_rbtree_t *rbtree; /* Allocate memory for it */ rbtree = (ldns_rbtree_t *) LDNS_MALLOC(ldns_rbtree_t); if (!rbtree) { return NULL; } /* Initialize it */ ldns_rbtree_init(rbtree, cmpf); return rbtree; } void ldns_rbtree_init(ldns_rbtree_t *rbtree, int (*cmpf)(const void *, const void *)) { /* Initialize it */ rbtree->root = LDNS_RBTREE_NULL; rbtree->count = 0; rbtree->cmp = cmpf; } void ldns_rbtree_free(ldns_rbtree_t *rbtree) { LDNS_FREE(rbtree); } /* * Rotates the node to the left. * */ static void ldns_rbtree_rotate_left(ldns_rbtree_t *rbtree, ldns_rbnode_t *node) { ldns_rbnode_t *right = node->right; node->right = right->left; if (right->left != LDNS_RBTREE_NULL) right->left->parent = node; right->parent = node->parent; if (node->parent != LDNS_RBTREE_NULL) { if (node == node->parent->left) { node->parent->left = right; } else { node->parent->right = right; } } else { rbtree->root = right; } right->left = node; node->parent = right; } /* * Rotates the node to the right. * */ static void ldns_rbtree_rotate_right(ldns_rbtree_t *rbtree, ldns_rbnode_t *node) { ldns_rbnode_t *left = node->left; node->left = left->right; if (left->right != LDNS_RBTREE_NULL) left->right->parent = node; left->parent = node->parent; if (node->parent != LDNS_RBTREE_NULL) { if (node == node->parent->right) { node->parent->right = left; } else { node->parent->left = left; } } else { rbtree->root = left; } left->right = node; node->parent = left; } static void ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node) { ldns_rbnode_t *uncle; /* While not at the root and need fixing... */ while (node != rbtree->root && node->parent->color == RED) { /* If our parent is left child of our grandparent... */ if (node->parent == node->parent->parent->left) { uncle = node->parent->parent->right; /* If our uncle is red... */ if (uncle->color == RED) { /* Paint the parent and the uncle black... */ node->parent->color = BLACK; uncle->color = BLACK; /* And the grandparent red... */ node->parent->parent->color = RED; /* And continue fixing the grandparent */ node = node->parent->parent; } else { /* Our uncle is black... */ /* Are we the right child? */ if (node == node->parent->right) { node = node->parent; ldns_rbtree_rotate_left(rbtree, node); } /* Now we're the left child, repaint and rotate... */ node->parent->color = BLACK; node->parent->parent->color = RED; ldns_rbtree_rotate_right(rbtree, node->parent->parent); } } else { uncle = node->parent->parent->left; /* If our uncle is red... */ if (uncle->color == RED) { /* Paint the parent and the uncle black... */ node->parent->color = BLACK; uncle->color = BLACK; /* And the grandparent red... */ node->parent->parent->color = RED; /* And continue fixing the grandparent */ node = node->parent->parent; } else { /* Our uncle is black... */ /* Are we the right child? */ if (node == node->parent->left) { node = node->parent; ldns_rbtree_rotate_right(rbtree, node); } /* Now we're the right child, repaint and rotate... */ node->parent->color = BLACK; node->parent->parent->color = RED; ldns_rbtree_rotate_left(rbtree, node->parent->parent); } } } rbtree->root->color = BLACK; } void ldns_rbtree_insert_vref(ldns_rbnode_t *data, void *rbtree) { (void) ldns_rbtree_insert((ldns_rbtree_t *) rbtree, data); } /* * Inserts a node into a red black tree. * * Returns NULL on failure or the pointer to the newly added node * otherwise. */ ldns_rbnode_t * ldns_rbtree_insert (ldns_rbtree_t *rbtree, ldns_rbnode_t *data) { /* XXX Not necessary, but keeps compiler quiet... */ int r = 0; /* We start at the root of the tree */ ldns_rbnode_t *node = rbtree->root; ldns_rbnode_t *parent = LDNS_RBTREE_NULL; /* Lets find the new parent... */ while (node != LDNS_RBTREE_NULL) { /* Compare two keys, do we have a duplicate? */ if ((r = rbtree->cmp(data->key, node->key)) == 0) { return NULL; } parent = node; if (r < 0) { node = node->left; } else { node = node->right; } } /* Initialize the new node */ data->parent = parent; data->left = data->right = LDNS_RBTREE_NULL; data->color = RED; rbtree->count++; /* Insert it into the tree... */ if (parent != LDNS_RBTREE_NULL) { if (r < 0) { parent->left = data; } else { parent->right = data; } } else { rbtree->root = data; } /* Fix up the red-black properties... */ ldns_rbtree_insert_fixup(rbtree, data); return data; } /* * Searches the red black tree, returns the data if key is found or NULL otherwise. * */ ldns_rbnode_t * ldns_rbtree_search (ldns_rbtree_t *rbtree, const void *key) { ldns_rbnode_t *node; if (ldns_rbtree_find_less_equal(rbtree, key, &node)) { return node; } else { return NULL; } } /** helpers for delete: swap node colours */ static void swap_int8(uint8_t* x, uint8_t* y) { uint8_t t = *x; *x = *y; *y = t; } /** helpers for delete: swap node pointers */ static void swap_np(ldns_rbnode_t** x, ldns_rbnode_t** y) { ldns_rbnode_t* t = *x; *x = *y; *y = t; } /** Update parent pointers of child trees of 'parent' */ static void change_parent_ptr(ldns_rbtree_t* rbtree, ldns_rbnode_t* parent, ldns_rbnode_t* old, ldns_rbnode_t* new) { if(parent == LDNS_RBTREE_NULL) { if(rbtree->root == old) rbtree->root = new; return; } if(parent->left == old) parent->left = new; if(parent->right == old) parent->right = new; } /** Update parent pointer of a node 'child' */ static void change_child_ptr(ldns_rbnode_t* child, ldns_rbnode_t* old, ldns_rbnode_t* new) { if(child == LDNS_RBTREE_NULL) return; if(child->parent == old) child->parent = new; } ldns_rbnode_t* ldns_rbtree_delete(ldns_rbtree_t *rbtree, const void *key) { ldns_rbnode_t *to_delete; ldns_rbnode_t *child; if((to_delete = ldns_rbtree_search(rbtree, key)) == 0) return 0; rbtree->count--; /* make sure we have at most one non-leaf child */ if(to_delete->left != LDNS_RBTREE_NULL && to_delete->right != LDNS_RBTREE_NULL) { /* swap with smallest from right subtree (or largest from left) */ ldns_rbnode_t *smright = to_delete->right; while(smright->left != LDNS_RBTREE_NULL) smright = smright->left; /* swap the smright and to_delete elements in the tree, * but the ldns_rbnode_t is first part of user data struct * so cannot just swap the keys and data pointers. Instead * readjust the pointers left,right,parent */ /* swap colors - colors are tied to the position in the tree */ swap_int8(&to_delete->color, &smright->color); /* swap child pointers in parents of smright/to_delete */ change_parent_ptr(rbtree, to_delete->parent, to_delete, smright); if(to_delete->right != smright) change_parent_ptr(rbtree, smright->parent, smright, to_delete); /* swap parent pointers in children of smright/to_delete */ change_child_ptr(smright->left, smright, to_delete); change_child_ptr(smright->left, smright, to_delete); change_child_ptr(smright->right, smright, to_delete); change_child_ptr(smright->right, smright, to_delete); change_child_ptr(to_delete->left, to_delete, smright); if(to_delete->right != smright) change_child_ptr(to_delete->right, to_delete, smright); if(to_delete->right == smright) { /* set up so after swap they work */ to_delete->right = to_delete; smright->parent = smright; } /* swap pointers in to_delete/smright nodes */ swap_np(&to_delete->parent, &smright->parent); swap_np(&to_delete->left, &smright->left); swap_np(&to_delete->right, &smright->right); /* now delete to_delete (which is at the location where the smright previously was) */ } if(to_delete->left != LDNS_RBTREE_NULL) child = to_delete->left; else child = to_delete->right; /* unlink to_delete from the tree, replace to_delete with child */ change_parent_ptr(rbtree, to_delete->parent, to_delete, child); change_child_ptr(child, to_delete, to_delete->parent); if(to_delete->color == RED) { /* if node is red then the child (black) can be swapped in */ } else if(child->color == RED) { /* change child to BLACK, removing a RED node is no problem */ if(child!=LDNS_RBTREE_NULL) child->color = BLACK; } else ldns_rbtree_delete_fixup(rbtree, child, to_delete->parent); /* unlink completely */ to_delete->parent = LDNS_RBTREE_NULL; to_delete->left = LDNS_RBTREE_NULL; to_delete->right = LDNS_RBTREE_NULL; to_delete->color = BLACK; return to_delete; } static void ldns_rbtree_delete_fixup(ldns_rbtree_t* rbtree, ldns_rbnode_t* child, ldns_rbnode_t* child_parent) { ldns_rbnode_t* sibling; int go_up = 1; /* determine sibling to the node that is one-black short */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; while(go_up) { if(child_parent == LDNS_RBTREE_NULL) { /* removed parent==black from root, every path, so ok */ return; } if(sibling->color == RED) { /* rotate to get a black sibling */ child_parent->color = RED; sibling->color = BLACK; if(child_parent->right == child) ldns_rbtree_rotate_right(rbtree, child_parent); else ldns_rbtree_rotate_left(rbtree, child_parent); /* new sibling after rotation */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } if(child_parent->color == BLACK && sibling->color == BLACK && sibling->left->color == BLACK && sibling->right->color == BLACK) { /* fixup local with recolor of sibling */ if(sibling != LDNS_RBTREE_NULL) sibling->color = RED; child = child_parent; child_parent = child_parent->parent; /* prepare to go up, new sibling */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } else go_up = 0; } if(child_parent->color == RED && sibling->color == BLACK && sibling->left->color == BLACK && sibling->right->color == BLACK) { /* move red to sibling to rebalance */ if(sibling != LDNS_RBTREE_NULL) sibling->color = RED; child_parent->color = BLACK; return; } /* get a new sibling, by rotating at sibling. See which child of sibling is red */ if(child_parent->right == child && sibling->color == BLACK && sibling->right->color == RED && sibling->left->color == BLACK) { sibling->color = RED; sibling->right->color = BLACK; ldns_rbtree_rotate_left(rbtree, sibling); /* new sibling after rotation */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } else if(child_parent->left == child && sibling->color == BLACK && sibling->left->color == RED && sibling->right->color == BLACK) { sibling->color = RED; sibling->left->color = BLACK; ldns_rbtree_rotate_right(rbtree, sibling); /* new sibling after rotation */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } /* now we have a black sibling with a red child. rotate and exchange colors. */ sibling->color = child_parent->color; child_parent->color = BLACK; if(child_parent->right == child) { sibling->left->color = BLACK; ldns_rbtree_rotate_right(rbtree, child_parent); } else { sibling->right->color = BLACK; ldns_rbtree_rotate_left(rbtree, child_parent); } } int ldns_rbtree_find_less_equal(ldns_rbtree_t *rbtree, const void *key, ldns_rbnode_t **result) { int r; ldns_rbnode_t *node; /* We start at root... */ node = rbtree->root; *result = NULL; /* While there are children... */ while (node != LDNS_RBTREE_NULL) { r = rbtree->cmp(key, node->key); if (r == 0) { /* Exact match */ *result = node; return 1; } if (r < 0) { node = node->left; } else { /* Temporary match */ *result = node; node = node->right; } } return 0; } /* * Finds the first element in the red black tree * */ ldns_rbnode_t * ldns_rbtree_first (ldns_rbtree_t *rbtree) { ldns_rbnode_t *node = rbtree->root; if (rbtree->root != LDNS_RBTREE_NULL) { for (node = rbtree->root; node->left != LDNS_RBTREE_NULL; node = node->left); } return node; } ldns_rbnode_t * ldns_rbtree_last (ldns_rbtree_t *rbtree) { ldns_rbnode_t *node = rbtree->root; if (rbtree->root != LDNS_RBTREE_NULL) { for (node = rbtree->root; node->right != LDNS_RBTREE_NULL; node = node->right); } return node; } /* * Returns the next node... * */ ldns_rbnode_t * ldns_rbtree_next (ldns_rbnode_t *node) { ldns_rbnode_t *parent; if (node->right != LDNS_RBTREE_NULL) { /* One right, then keep on going left... */ for (node = node->right; node->left != LDNS_RBTREE_NULL; node = node->left); } else { parent = node->parent; while (parent != LDNS_RBTREE_NULL && node == parent->right) { node = parent; parent = parent->parent; } node = parent; } return node; } ldns_rbnode_t * ldns_rbtree_previous(ldns_rbnode_t *node) { ldns_rbnode_t *parent; if (node->left != LDNS_RBTREE_NULL) { /* One left, then keep on going right... */ for (node = node->left; node->right != LDNS_RBTREE_NULL; node = node->right); } else { parent = node->parent; while (parent != LDNS_RBTREE_NULL && node == parent->left) { node = parent; parent = parent->parent; } node = parent; } return node; } /** * split off elements number of elements from the start * of the name tree and return a new tree */ ldns_rbtree_t * ldns_rbtree_split(ldns_rbtree_t *tree, size_t elements) { ldns_rbtree_t *new_tree; ldns_rbnode_t *cur_node; ldns_rbnode_t *move_node; size_t count = 0; new_tree = ldns_rbtree_create(tree->cmp); cur_node = ldns_rbtree_first(tree); while (count < elements && cur_node != LDNS_RBTREE_NULL) { move_node = ldns_rbtree_delete(tree, cur_node->key); (void)ldns_rbtree_insert(new_tree, move_node); cur_node = ldns_rbtree_first(tree); count++; } return new_tree; } /* * add all node from the second tree to the first (removing them from the * second), and fix up nsec(3)s if present */ void ldns_rbtree_join(ldns_rbtree_t *tree1, ldns_rbtree_t *tree2) { ldns_traverse_postorder(tree2, ldns_rbtree_insert_vref, tree1); } /** recursive descent traverse */ static void traverse_post(void (*func)(ldns_rbnode_t*, void*), void* arg, ldns_rbnode_t* node) { if(!node || node == LDNS_RBTREE_NULL) return; /* recurse */ traverse_post(func, arg, node->left); traverse_post(func, arg, node->right); /* call user func */ (*func)(node, arg); } void ldns_traverse_postorder(ldns_rbtree_t* tree, void (*func)(ldns_rbnode_t*, void*), void* arg) { traverse_post(func, arg, tree->root); } Net-LDNS-0.75/src/ldns/rdata.c000644 000770 000024 00000037766 12502772424 016332 0ustar00calledstaff000000 000000 /* * rdata.c * * rdata implementation * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include /* * Access functions * do this as functions to get type checking */ /* read */ size_t ldns_rdf_size(const ldns_rdf *rd) { assert(rd != NULL); return rd->_size; } ldns_rdf_type ldns_rdf_get_type(const ldns_rdf *rd) { assert(rd != NULL); return rd->_type; } uint8_t * ldns_rdf_data(const ldns_rdf *rd) { assert(rd != NULL); return rd->_data; } /* write */ void ldns_rdf_set_size(ldns_rdf *rd, size_t size) { assert(rd != NULL); rd->_size = size; } void ldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type) { assert(rd != NULL); rd->_type = type; } void ldns_rdf_set_data(ldns_rdf *rd, void *data) { /* only copy the pointer */ assert(rd != NULL); rd->_data = data; } /* for types that allow it, return * the native/host order type */ uint8_t ldns_rdf2native_int8(const ldns_rdf *rd) { uint8_t data; /* only allow 8 bit rdfs */ if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_BYTE) { return 0; } memcpy(&data, ldns_rdf_data(rd), sizeof(data)); return data; } uint16_t ldns_rdf2native_int16(const ldns_rdf *rd) { uint16_t data; /* only allow 16 bit rdfs */ if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_WORD) { return 0; } memcpy(&data, ldns_rdf_data(rd), sizeof(data)); return ntohs(data); } uint32_t ldns_rdf2native_int32(const ldns_rdf *rd) { uint32_t data; /* only allow 32 bit rdfs */ if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD) { return 0; } memcpy(&data, ldns_rdf_data(rd), sizeof(data)); return ntohl(data); } time_t ldns_rdf2native_time_t(const ldns_rdf *rd) { uint32_t data; /* only allow 32 bit rdfs */ if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD || ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_TIME) { return 0; } memcpy(&data, ldns_rdf_data(rd), sizeof(data)); return (time_t)ntohl(data); } ldns_rdf * ldns_native2rdf_int8(ldns_rdf_type type, uint8_t value) { return ldns_rdf_new_frm_data(type, LDNS_RDF_SIZE_BYTE, &value); } ldns_rdf * ldns_native2rdf_int16(ldns_rdf_type type, uint16_t value) { uint16_t *rdf_data = LDNS_XMALLOC(uint16_t, 1); ldns_rdf* rdf; if (!rdf_data) { return NULL; } ldns_write_uint16(rdf_data, value); rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_WORD, rdf_data); if(!rdf) LDNS_FREE(rdf_data); return rdf; } ldns_rdf * ldns_native2rdf_int32(ldns_rdf_type type, uint32_t value) { uint32_t *rdf_data = LDNS_XMALLOC(uint32_t, 1); ldns_rdf* rdf; if (!rdf_data) { return NULL; } ldns_write_uint32(rdf_data, value); rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_DOUBLEWORD, rdf_data); if(!rdf) LDNS_FREE(rdf_data); return rdf; } ldns_rdf * ldns_native2rdf_int16_data(size_t size, uint8_t *data) { uint8_t *rdf_data = LDNS_XMALLOC(uint8_t, size + 2); ldns_rdf* rdf; if (!rdf_data) { return NULL; } ldns_write_uint16(rdf_data, size); memcpy(rdf_data + 2, data, size); rdf = ldns_rdf_new(LDNS_RDF_TYPE_INT16_DATA, size + 2, rdf_data); if(!rdf) LDNS_FREE(rdf_data); return rdf; } /* note: data must be allocated memory */ ldns_rdf * ldns_rdf_new(ldns_rdf_type type, size_t size, void *data) { ldns_rdf *rd; rd = LDNS_MALLOC(ldns_rdf); if (!rd) { return NULL; } ldns_rdf_set_size(rd, size); ldns_rdf_set_type(rd, type); ldns_rdf_set_data(rd, data); return rd; } ldns_rdf * ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data) { ldns_rdf *rdf; /* if the size is too big, fail */ if (size > LDNS_MAX_RDFLEN) { return NULL; } /* allocate space */ rdf = LDNS_MALLOC(ldns_rdf); if (!rdf) { return NULL; } rdf->_data = LDNS_XMALLOC(uint8_t, size); if (!rdf->_data) { LDNS_FREE(rdf); return NULL; } /* set the values */ ldns_rdf_set_type(rdf, type); ldns_rdf_set_size(rdf, size); memcpy(rdf->_data, data, size); return rdf; } ldns_rdf * ldns_rdf_clone(const ldns_rdf *rd) { assert(rd != NULL); return (ldns_rdf_new_frm_data( ldns_rdf_get_type(rd), ldns_rdf_size(rd), ldns_rdf_data(rd))); } void ldns_rdf_deep_free(ldns_rdf *rd) { if (rd) { if (rd->_data) { LDNS_FREE(rd->_data); } LDNS_FREE(rd); } } void ldns_rdf_free(ldns_rdf *rd) { if (rd) { LDNS_FREE(rd); } } ldns_rdf * ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str) { ldns_rdf *rdf = NULL; ldns_status status; switch (type) { case LDNS_RDF_TYPE_DNAME: status = ldns_str2rdf_dname(&rdf, str); break; case LDNS_RDF_TYPE_INT8: status = ldns_str2rdf_int8(&rdf, str); break; case LDNS_RDF_TYPE_INT16: status = ldns_str2rdf_int16(&rdf, str); break; case LDNS_RDF_TYPE_INT32: status = ldns_str2rdf_int32(&rdf, str); break; case LDNS_RDF_TYPE_A: status = ldns_str2rdf_a(&rdf, str); break; case LDNS_RDF_TYPE_AAAA: status = ldns_str2rdf_aaaa(&rdf, str); break; case LDNS_RDF_TYPE_STR: status = ldns_str2rdf_str(&rdf, str); break; case LDNS_RDF_TYPE_APL: status = ldns_str2rdf_apl(&rdf, str); break; case LDNS_RDF_TYPE_B64: status = ldns_str2rdf_b64(&rdf, str); break; case LDNS_RDF_TYPE_B32_EXT: status = ldns_str2rdf_b32_ext(&rdf, str); break; case LDNS_RDF_TYPE_HEX: status = ldns_str2rdf_hex(&rdf, str); break; case LDNS_RDF_TYPE_NSEC: status = ldns_str2rdf_nsec(&rdf, str); break; case LDNS_RDF_TYPE_TYPE: status = ldns_str2rdf_type(&rdf, str); break; case LDNS_RDF_TYPE_CLASS: status = ldns_str2rdf_class(&rdf, str); break; case LDNS_RDF_TYPE_CERT_ALG: status = ldns_str2rdf_cert_alg(&rdf, str); break; case LDNS_RDF_TYPE_ALG: status = ldns_str2rdf_alg(&rdf, str); break; case LDNS_RDF_TYPE_UNKNOWN: status = ldns_str2rdf_unknown(&rdf, str); break; case LDNS_RDF_TYPE_TIME: status = ldns_str2rdf_time(&rdf, str); break; case LDNS_RDF_TYPE_PERIOD: status = ldns_str2rdf_period(&rdf, str); break; case LDNS_RDF_TYPE_HIP: status = ldns_str2rdf_hip(&rdf, str); break; case LDNS_RDF_TYPE_SERVICE: status = ldns_str2rdf_service(&rdf, str); break; case LDNS_RDF_TYPE_LOC: status = ldns_str2rdf_loc(&rdf, str); break; case LDNS_RDF_TYPE_WKS: status = ldns_str2rdf_wks(&rdf, str); break; case LDNS_RDF_TYPE_NSAP: status = ldns_str2rdf_nsap(&rdf, str); break; case LDNS_RDF_TYPE_ATMA: status = ldns_str2rdf_atma(&rdf, str); break; case LDNS_RDF_TYPE_IPSECKEY: status = ldns_str2rdf_ipseckey(&rdf, str); break; case LDNS_RDF_TYPE_NSEC3_SALT: status = ldns_str2rdf_nsec3_salt(&rdf, str); break; case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: status = ldns_str2rdf_b32_ext(&rdf, str); break; case LDNS_RDF_TYPE_ILNP64: status = ldns_str2rdf_ilnp64(&rdf, str); break; case LDNS_RDF_TYPE_EUI48: status = ldns_str2rdf_eui48(&rdf, str); break; case LDNS_RDF_TYPE_EUI64: status = ldns_str2rdf_eui64(&rdf, str); break; case LDNS_RDF_TYPE_TAG: status = ldns_str2rdf_tag(&rdf, str); break; case LDNS_RDF_TYPE_LONG_STR: status = ldns_str2rdf_long_str(&rdf, str); break; case LDNS_RDF_TYPE_CERTIFICATE_USAGE: status = ldns_str2rdf_certificate_usage(&rdf, str); break; case LDNS_RDF_TYPE_SELECTOR: status = ldns_str2rdf_selector(&rdf, str); break; case LDNS_RDF_TYPE_MATCHING_TYPE: status = ldns_str2rdf_matching_type(&rdf, str); break; case LDNS_RDF_TYPE_NONE: default: /* default default ??? */ status = LDNS_STATUS_ERR; break; } if (LDNS_STATUS_OK == status) { ldns_rdf_set_type(rdf, type); return rdf; } if (rdf) { LDNS_FREE(rdf); } return NULL; } ldns_status ldns_rdf_new_frm_fp(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp) { return ldns_rdf_new_frm_fp_l(rdf, type, fp, NULL); } ldns_status ldns_rdf_new_frm_fp_l(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp, int *line_nr) { char *line; ldns_rdf *r; ssize_t t; line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1); if (!line) { return LDNS_STATUS_MEM_ERR; } /* read an entire line in from the file */ if ((t = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, 0, line_nr)) == -1 || t == 0) { LDNS_FREE(line); return LDNS_STATUS_SYNTAX_RDATA_ERR; } r = ldns_rdf_new_frm_str(type, (const char*) line); LDNS_FREE(line); if (rdf) { *rdf = r; return LDNS_STATUS_OK; } else { return LDNS_STATUS_NULL; } } ldns_rdf * ldns_rdf_address_reverse(ldns_rdf *rd) { uint8_t buf_4[LDNS_IP4ADDRLEN]; uint8_t buf_6[LDNS_IP6ADDRLEN * 2]; ldns_rdf *rev; ldns_rdf *in_addr; ldns_rdf *ret_dname; uint8_t octet; uint8_t nnibble; uint8_t nibble; uint8_t i, j; char *char_dname; int nbit; if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_A && ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_AAAA) { return NULL; } in_addr = NULL; ret_dname = NULL; switch(ldns_rdf_get_type(rd)) { case LDNS_RDF_TYPE_A: /* the length of the buffer is 4 */ buf_4[3] = ldns_rdf_data(rd)[0]; buf_4[2] = ldns_rdf_data(rd)[1]; buf_4[1] = ldns_rdf_data(rd)[2]; buf_4[0] = ldns_rdf_data(rd)[3]; in_addr = ldns_dname_new_frm_str("in-addr.arpa."); if (!in_addr) { return NULL; } /* make a new rdf and convert that back */ rev = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_A, LDNS_IP4ADDRLEN, (void*)&buf_4); if (!rev) { LDNS_FREE(in_addr); return NULL; } /* convert rev to a string */ char_dname = ldns_rdf2str(rev); if (!char_dname) { LDNS_FREE(in_addr); ldns_rdf_deep_free(rev); return NULL; } /* transform back to rdf with type dname */ ret_dname = ldns_dname_new_frm_str(char_dname); if (!ret_dname) { LDNS_FREE(in_addr); ldns_rdf_deep_free(rev); LDNS_FREE(char_dname); return NULL; } /* not needed anymore */ ldns_rdf_deep_free(rev); LDNS_FREE(char_dname); break; case LDNS_RDF_TYPE_AAAA: /* some foo magic to reverse the nibbles ... */ for (nbit = 127; nbit >= 0; nbit = nbit - 4) { /* calculate octett (8 bit) */ octet = ( ((unsigned int) nbit) & 0x78) >> 3; /* calculate nibble */ nnibble = ( ((unsigned int) nbit) & 0x04) >> 2; /* extract nibble */ nibble = (ldns_rdf_data(rd)[octet] & ( 0xf << (4 * (1 - nnibble)) ) ) >> ( 4 * (1 - nnibble)); buf_6[(LDNS_IP6ADDRLEN * 2 - 1) - (octet * 2 + nnibble)] = (uint8_t)ldns_int_to_hexdigit((int)nibble); } char_dname = LDNS_XMALLOC(char, (LDNS_IP6ADDRLEN * 4)); if (!char_dname) { return NULL; } char_dname[LDNS_IP6ADDRLEN * 4 - 1] = '\0'; /* closure */ /* walk the string and add . 's */ for (i = 0, j = 0; i < LDNS_IP6ADDRLEN * 2; i++, j = j + 2) { char_dname[j] = (char)buf_6[i]; if (i != LDNS_IP6ADDRLEN * 2 - 1) { char_dname[j + 1] = '.'; } } in_addr = ldns_dname_new_frm_str("ip6.arpa."); if (!in_addr) { LDNS_FREE(char_dname); return NULL; } /* convert rev to a string */ ret_dname = ldns_dname_new_frm_str(char_dname); LDNS_FREE(char_dname); if (!ret_dname) { ldns_rdf_deep_free(in_addr); return NULL; } break; default: break; } /* add the suffix */ rev = ldns_dname_cat_clone(ret_dname, in_addr); ldns_rdf_deep_free(ret_dname); ldns_rdf_deep_free(in_addr); return rev; } ldns_status ldns_rdf_hip_get_alg_hit_pk(ldns_rdf *rdf, uint8_t* alg, uint8_t *hit_size, uint8_t** hit, uint16_t *pk_size, uint8_t** pk) { uint8_t *data; size_t rdf_size; if (! rdf || ! alg || ! hit || ! hit_size || ! pk || ! pk_size) { return LDNS_STATUS_INVALID_POINTER; } else if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_HIP) { return LDNS_STATUS_INVALID_RDF_TYPE; } else if ((rdf_size = ldns_rdf_size(rdf)) < 6) { return LDNS_STATUS_WIRE_RDATA_ERR; } data = ldns_rdf_data(rdf); *hit_size = data[0]; *alg = data[1]; *pk_size = ldns_read_uint16(data + 2); *hit = data + 4; *pk = data + 4 + *hit_size; if (*hit_size == 0 || *pk_size == 0 || rdf_size < (size_t) *hit_size + *pk_size + 4) { return LDNS_STATUS_WIRE_RDATA_ERR; } return LDNS_STATUS_OK; } ldns_status ldns_rdf_hip_new_frm_alg_hit_pk(ldns_rdf** rdf, uint8_t alg, uint8_t hit_size, uint8_t *hit, uint16_t pk_size, uint8_t *pk) { uint8_t *data; if (! rdf) { return LDNS_STATUS_INVALID_POINTER; } if (4 + hit_size + pk_size > LDNS_MAX_RDFLEN) { return LDNS_STATUS_RDATA_OVERFLOW; } data = LDNS_XMALLOC(uint8_t, 4 + hit_size + pk_size); if (data == NULL) { return LDNS_STATUS_MEM_ERR; } data[0] = hit_size; data[1] = alg; ldns_write_uint16(data + 2, pk_size); memcpy(data + 4, hit, hit_size); memcpy(data + 4 + hit_size, pk, pk_size); *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HIP, 4 + hit_size + pk_size, data); if (! *rdf) { LDNS_FREE(data); return LDNS_STATUS_MEM_ERR; } return LDNS_STATUS_OK; } ldns_status ldns_octet(char *word, size_t *length) { char *s; char *p; *length = 0; for (s = p = word; *s != '\0'; s++,p++) { switch (*s) { case '.': if (s[1] == '.') { return LDNS_STATUS_EMPTY_LABEL; } *p = *s; (*length)++; break; case '\\': if ('0' <= s[1] && s[1] <= '9' && '0' <= s[2] && s[2] <= '9' && '0' <= s[3] && s[3] <= '9') { /* \DDD seen */ int val = ((s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0')); if (0 <= val && val <= 255) { /* this also handles \0 */ s += 3; *p = val; (*length)++; } else { return LDNS_STATUS_DDD_OVERFLOW; } } else { /* an espaced character, like \ ? * remove the '\' keep the rest */ *p = *++s; (*length)++; } break; case '\"': /* non quoted " Is either first or the last character in * the string */ *p = *++s; /* skip it */ (*length)++; /* I'm not sure if this is needed in libdns... MG */ if ( *s == '\0' ) { /* ok, it was the last one */ *p = '\0'; return LDNS_STATUS_OK; } break; default: *p = *s; (*length)++; break; } } *p = '\0'; return LDNS_STATUS_OK; } int ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2) { uint16_t i1, i2, i; uint8_t *d1, *d2; /* only when both are not NULL we can say anything about them */ if (!rd1 && !rd2) { return 0; } if (!rd1 || !rd2) { return -1; } i1 = ldns_rdf_size(rd1); i2 = ldns_rdf_size(rd2); if (i1 < i2) { return -1; } else if (i1 > i2) { return +1; } else { d1 = (uint8_t*)ldns_rdf_data(rd1); d2 = (uint8_t*)ldns_rdf_data(rd2); for(i = 0; i < i1; i++) { if (d1[i] < d2[i]) { return -1; } else if (d1[i] > d2[i]) { return +1; } } } return 0; } uint32_t ldns_str2period(const char *nptr, const char **endptr) { int sign = 0; uint32_t i = 0; uint32_t seconds = 0; for(*endptr = nptr; **endptr; (*endptr)++) { switch (**endptr) { case ' ': case '\t': break; case '-': if(sign == 0) { sign = -1; } else { return seconds; } break; case '+': if(sign == 0) { sign = 1; } else { return seconds; } break; case 's': case 'S': seconds += i; i = 0; break; case 'm': case 'M': seconds += i * 60; i = 0; break; case 'h': case 'H': seconds += i * 60 * 60; i = 0; break; case 'd': case 'D': seconds += i * 60 * 60 * 24; i = 0; break; case 'w': case 'W': seconds += i * 60 * 60 * 24 * 7; i = 0; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': i *= 10; i += (**endptr - '0'); break; default: seconds += i; /* disregard signedness */ return seconds; } } seconds += i; /* disregard signedness */ return seconds; } Net-LDNS-0.75/src/ldns/resolver.c000644 000770 000024 00000107574 12471046240 017066 0ustar00calledstaff000000 000000 /* * resolver.c * * resolver implementation * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include #include /* Access function for reading * and setting the different Resolver * options */ /* read */ uint16_t ldns_resolver_port(const ldns_resolver *r) { return r->_port; } ldns_rdf * ldns_resolver_source(const ldns_resolver *r) { return r->_source; } uint16_t ldns_resolver_edns_udp_size(const ldns_resolver *r) { return r->_edns_udp_size; } uint8_t ldns_resolver_retry(const ldns_resolver *r) { return r->_retry; } uint8_t ldns_resolver_retrans(const ldns_resolver *r) { return r->_retrans; } bool ldns_resolver_fallback(const ldns_resolver *r) { return r->_fallback; } uint8_t ldns_resolver_ip6(const ldns_resolver *r) { return r->_ip6; } bool ldns_resolver_recursive(const ldns_resolver *r) { return r->_recursive; } bool ldns_resolver_debug(const ldns_resolver *r) { return r->_debug; } bool ldns_resolver_dnsrch(const ldns_resolver *r) { return r->_dnsrch; } bool ldns_resolver_fail(const ldns_resolver *r) { return r->_fail; } bool ldns_resolver_defnames(const ldns_resolver *r) { return r->_defnames; } ldns_rdf * ldns_resolver_domain(const ldns_resolver *r) { return r->_domain; } ldns_rdf ** ldns_resolver_searchlist(const ldns_resolver *r) { return r->_searchlist; } ldns_rdf ** ldns_resolver_nameservers(const ldns_resolver *r) { return r->_nameservers; } size_t ldns_resolver_nameserver_count(const ldns_resolver *r) { return r->_nameserver_count; } bool ldns_resolver_dnssec(const ldns_resolver *r) { return r->_dnssec; } bool ldns_resolver_dnssec_cd(const ldns_resolver *r) { return r->_dnssec_cd; } ldns_rr_list * ldns_resolver_dnssec_anchors(const ldns_resolver *r) { return r->_dnssec_anchors; } bool ldns_resolver_trusted_key(const ldns_resolver *r, ldns_rr_list * keys, ldns_rr_list * trusted_keys) { size_t i; bool result = false; ldns_rr_list * trust_anchors; ldns_rr * cur_rr; if (!r || !keys) { return false; } trust_anchors = ldns_resolver_dnssec_anchors(r); if (!trust_anchors) { return false; } for (i = 0; i < ldns_rr_list_rr_count(keys); i++) { cur_rr = ldns_rr_list_rr(keys, i); if (ldns_rr_list_contains_rr(trust_anchors, cur_rr)) { if (trusted_keys) { ldns_rr_list_push_rr(trusted_keys, cur_rr); } result = true; } } return result; } bool ldns_resolver_igntc(const ldns_resolver *r) { return r->_igntc; } bool ldns_resolver_usevc(const ldns_resolver *r) { return r->_usevc; } size_t * ldns_resolver_rtt(const ldns_resolver *r) { return r->_rtt; } size_t ldns_resolver_nameserver_rtt(const ldns_resolver *r, size_t pos) { size_t *rtt; assert(r != NULL); rtt = ldns_resolver_rtt(r); if (pos >= ldns_resolver_nameserver_count(r)) { /* error ?*/ return 0; } else { return rtt[pos]; } } struct timeval ldns_resolver_timeout(const ldns_resolver *r) { return r->_timeout; } char * ldns_resolver_tsig_keyname(const ldns_resolver *r) { return r->_tsig_keyname; } char * ldns_resolver_tsig_algorithm(const ldns_resolver *r) { return r->_tsig_algorithm; } char * ldns_resolver_tsig_keydata(const ldns_resolver *r) { return r->_tsig_keydata; } bool ldns_resolver_random(const ldns_resolver *r) { return r->_random; } size_t ldns_resolver_searchlist_count(const ldns_resolver *r) { return r->_searchlist_count; } /* write */ void ldns_resolver_set_port(ldns_resolver *r, uint16_t p) { r->_port = p; } void ldns_resolver_set_source(ldns_resolver *r, ldns_rdf *s) { r->_source = s; } ldns_rdf * ldns_resolver_pop_nameserver(ldns_resolver *r) { ldns_rdf **nameservers; ldns_rdf *pop; size_t ns_count; size_t *rtt; assert(r != NULL); ns_count = ldns_resolver_nameserver_count(r); nameservers = ldns_resolver_nameservers(r); rtt = ldns_resolver_rtt(r); if (ns_count == 0 || !nameservers) { return NULL; } pop = nameservers[ns_count - 1]; if (ns_count == 1) { LDNS_FREE(nameservers); LDNS_FREE(rtt); ldns_resolver_set_nameservers(r, NULL); ldns_resolver_set_rtt(r, NULL); } else { nameservers = LDNS_XREALLOC(nameservers, ldns_rdf *, (ns_count - 1)); rtt = LDNS_XREALLOC(rtt, size_t, (ns_count - 1)); ldns_resolver_set_nameservers(r, nameservers); ldns_resolver_set_rtt(r, rtt); } /* decr the count */ ldns_resolver_dec_nameserver_count(r); return pop; } ldns_status ldns_resolver_push_nameserver(ldns_resolver *r, ldns_rdf *n) { ldns_rdf **nameservers; size_t ns_count; size_t *rtt; if (ldns_rdf_get_type(n) != LDNS_RDF_TYPE_A && ldns_rdf_get_type(n) != LDNS_RDF_TYPE_AAAA) { return LDNS_STATUS_ERR; } ns_count = ldns_resolver_nameserver_count(r); nameservers = ldns_resolver_nameservers(r); rtt = ldns_resolver_rtt(r); /* make room for the next one */ if (ns_count == 0) { nameservers = LDNS_XMALLOC(ldns_rdf *, 1); } else { nameservers = LDNS_XREALLOC(nameservers, ldns_rdf *, (ns_count + 1)); } if(!nameservers) return LDNS_STATUS_MEM_ERR; /* set the new value in the resolver */ ldns_resolver_set_nameservers(r, nameservers); /* don't forget the rtt */ if (ns_count == 0) { rtt = LDNS_XMALLOC(size_t, 1); } else { rtt = LDNS_XREALLOC(rtt, size_t, (ns_count + 1)); } if(!rtt) return LDNS_STATUS_MEM_ERR; /* slide n in its slot. */ /* we clone it here, because then we can free the original * rr's where it stood */ nameservers[ns_count] = ldns_rdf_clone(n); rtt[ns_count] = LDNS_RESOLV_RTT_MIN; ldns_resolver_incr_nameserver_count(r); ldns_resolver_set_rtt(r, rtt); return LDNS_STATUS_OK; } ldns_status ldns_resolver_push_nameserver_rr(ldns_resolver *r, ldns_rr *rr) { ldns_rdf *address; if ((!rr) || (ldns_rr_get_type(rr) != LDNS_RR_TYPE_A && ldns_rr_get_type(rr) != LDNS_RR_TYPE_AAAA)) { return LDNS_STATUS_ERR; } address = ldns_rr_rdf(rr, 0); /* extract the ip number */ if (address) { return ldns_resolver_push_nameserver(r, address); } else { return LDNS_STATUS_ERR; } } ldns_status ldns_resolver_push_nameserver_rr_list(ldns_resolver *r, ldns_rr_list *rrlist) { ldns_rr *rr; ldns_status stat; size_t i; stat = LDNS_STATUS_OK; if (rrlist) { for(i = 0; i < ldns_rr_list_rr_count(rrlist); i++) { rr = ldns_rr_list_rr(rrlist, i); if (ldns_resolver_push_nameserver_rr(r, rr) != LDNS_STATUS_OK) { stat = LDNS_STATUS_ERR; break; } } return stat; } else { return LDNS_STATUS_ERR; } } void ldns_resolver_set_edns_udp_size(ldns_resolver *r, uint16_t s) { r->_edns_udp_size = s; } void ldns_resolver_set_recursive(ldns_resolver *r, bool re) { r->_recursive = re; } void ldns_resolver_set_dnssec(ldns_resolver *r, bool d) { r->_dnssec = d; } void ldns_resolver_set_dnssec_cd(ldns_resolver *r, bool d) { r->_dnssec_cd = d; } void ldns_resolver_set_dnssec_anchors(ldns_resolver *r, ldns_rr_list * l) { r->_dnssec_anchors = l; } ldns_status ldns_resolver_push_dnssec_anchor(ldns_resolver *r, ldns_rr *rr) { ldns_rr_list * trust_anchors; if ((!rr) || (ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY && ldns_rr_get_type(rr) != LDNS_RR_TYPE_DS)) { return LDNS_STATUS_ERR; } if (!(trust_anchors = ldns_resolver_dnssec_anchors(r))) { /* Initialize */ trust_anchors = ldns_rr_list_new(); ldns_resolver_set_dnssec_anchors(r, trust_anchors); } return (ldns_rr_list_push_rr(trust_anchors, ldns_rr_clone(rr))) ? LDNS_STATUS_OK : LDNS_STATUS_ERR; } void ldns_resolver_set_igntc(ldns_resolver *r, bool i) { r->_igntc = i; } void ldns_resolver_set_usevc(ldns_resolver *r, bool vc) { r->_usevc = vc; } void ldns_resolver_set_debug(ldns_resolver *r, bool d) { r->_debug = d; } void ldns_resolver_set_ip6(ldns_resolver *r, uint8_t ip6) { r->_ip6 = ip6; } void ldns_resolver_set_fail(ldns_resolver *r, bool f) { r->_fail =f; } static void ldns_resolver_set_searchlist_count(ldns_resolver *r, size_t c) { r->_searchlist_count = c; } void ldns_resolver_set_nameserver_count(ldns_resolver *r, size_t c) { r->_nameserver_count = c; } void ldns_resolver_set_dnsrch(ldns_resolver *r, bool d) { r->_dnsrch = d; } void ldns_resolver_set_retry(ldns_resolver *r, uint8_t retry) { r->_retry = retry; } void ldns_resolver_set_retrans(ldns_resolver *r, uint8_t retrans) { r->_retrans = retrans; } void ldns_resolver_set_fallback(ldns_resolver *r, bool fallback) { r->_fallback = fallback; } void ldns_resolver_set_nameservers(ldns_resolver *r, ldns_rdf **n) { r->_nameservers = n; } void ldns_resolver_set_defnames(ldns_resolver *r, bool d) { r->_defnames = d; } void ldns_resolver_set_rtt(ldns_resolver *r, size_t *rtt) { r->_rtt = rtt; } void ldns_resolver_set_nameserver_rtt(ldns_resolver *r, size_t pos, size_t value) { size_t *rtt; assert(r != NULL); rtt = ldns_resolver_rtt(r); if (pos >= ldns_resolver_nameserver_count(r)) { /* error ?*/ } else { rtt[pos] = value; } } void ldns_resolver_incr_nameserver_count(ldns_resolver *r) { size_t c; c = ldns_resolver_nameserver_count(r); ldns_resolver_set_nameserver_count(r, ++c); } void ldns_resolver_dec_nameserver_count(ldns_resolver *r) { size_t c; c = ldns_resolver_nameserver_count(r); if (c == 0) { return; } else { ldns_resolver_set_nameserver_count(r, --c); } } void ldns_resolver_set_domain(ldns_resolver *r, ldns_rdf *d) { r->_domain = d; } void ldns_resolver_set_timeout(ldns_resolver *r, struct timeval timeout) { r->_timeout.tv_sec = timeout.tv_sec; r->_timeout.tv_usec = timeout.tv_usec; } void ldns_resolver_push_searchlist(ldns_resolver *r, ldns_rdf *d) { ldns_rdf **searchlist; size_t list_count; if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) { return; } list_count = ldns_resolver_searchlist_count(r); searchlist = ldns_resolver_searchlist(r); searchlist = LDNS_XREALLOC(searchlist, ldns_rdf *, (list_count + 1)); if (searchlist) { r->_searchlist = searchlist; searchlist[list_count] = ldns_rdf_clone(d); ldns_resolver_set_searchlist_count(r, list_count + 1); } /* no way to report mem err */ } void ldns_resolver_set_tsig_keyname(ldns_resolver *r, char *tsig_keyname) { LDNS_FREE(r->_tsig_keyname); r->_tsig_keyname = strdup(tsig_keyname); } void ldns_resolver_set_tsig_algorithm(ldns_resolver *r, char *tsig_algorithm) { LDNS_FREE(r->_tsig_algorithm); r->_tsig_algorithm = strdup(tsig_algorithm); } void ldns_resolver_set_tsig_keydata(ldns_resolver *r, char *tsig_keydata) { LDNS_FREE(r->_tsig_keydata); r->_tsig_keydata = strdup(tsig_keydata); } void ldns_resolver_set_random(ldns_resolver *r, bool b) { r->_random = b; } /* more sophisticated functions */ ldns_resolver * ldns_resolver_new(void) { ldns_resolver *r; r = LDNS_MALLOC(ldns_resolver); if (!r) { return NULL; } r->_searchlist = NULL; r->_nameservers = NULL; r->_rtt = NULL; /* defaults are filled out */ ldns_resolver_set_searchlist_count(r, 0); ldns_resolver_set_nameserver_count(r, 0); ldns_resolver_set_usevc(r, 0); ldns_resolver_set_port(r, LDNS_PORT); ldns_resolver_set_domain(r, NULL); ldns_resolver_set_defnames(r, false); ldns_resolver_set_retry(r, 3); ldns_resolver_set_retrans(r, 2); ldns_resolver_set_fallback(r, true); ldns_resolver_set_fail(r, false); ldns_resolver_set_edns_udp_size(r, 0); ldns_resolver_set_dnssec(r, false); ldns_resolver_set_dnssec_cd(r, false); ldns_resolver_set_dnssec_anchors(r, NULL); ldns_resolver_set_ip6(r, LDNS_RESOLV_INETANY); ldns_resolver_set_igntc(r, false); ldns_resolver_set_recursive(r, false); ldns_resolver_set_dnsrch(r, true); ldns_resolver_set_source(r, NULL); ldns_resolver_set_ixfr_serial(r, 0); /* randomize the nameserver to be queried * when there are multiple */ ldns_resolver_set_random(r, true); ldns_resolver_set_debug(r, 0); r->_timeout.tv_sec = LDNS_DEFAULT_TIMEOUT_SEC; r->_timeout.tv_usec = LDNS_DEFAULT_TIMEOUT_USEC; /* TODO: fd=0 is actually a valid socket (stdin), replace with -1 */ r->_socket = 0; r->_axfr_soa_count = 0; r->_axfr_i = 0; r->_cur_axfr_pkt = NULL; r->_tsig_keyname = NULL; r->_tsig_keydata = NULL; r->_tsig_algorithm = NULL; return r; } ldns_resolver * ldns_resolver_clone(ldns_resolver *src) { ldns_resolver *dst; size_t i; assert(src != NULL); if (!(dst = LDNS_MALLOC(ldns_resolver))) return NULL; (void) memcpy(dst, src, sizeof(ldns_resolver)); if (dst->_searchlist_count == 0) dst->_searchlist = NULL; else { if (!(dst->_searchlist = LDNS_XMALLOC(ldns_rdf *, dst->_searchlist_count))) goto error; for (i = 0; i < dst->_searchlist_count; i++) if (!(dst->_searchlist[i] = ldns_rdf_clone(src->_searchlist[i]))) { dst->_searchlist_count = i; goto error_searchlist; } } if (dst->_nameserver_count == 0) { dst->_nameservers = NULL; dst->_rtt = NULL; } else { if (!(dst->_nameservers = LDNS_XMALLOC(ldns_rdf *, dst->_nameserver_count))) goto error_searchlist; for (i = 0; i < dst->_nameserver_count; i++) if (!(dst->_nameservers[i] = ldns_rdf_clone(src->_nameservers[i]))) { dst->_nameserver_count = i; goto error_nameservers; } if (!(dst->_rtt = LDNS_XMALLOC(size_t, dst->_nameserver_count))) goto error_nameservers; (void) memcpy(dst->_rtt, src->_rtt, sizeof(size_t) * dst->_nameserver_count); } if (dst->_domain && (!(dst->_domain = ldns_rdf_clone(src->_domain)))) goto error_rtt; if (dst->_tsig_keyname && (!(dst->_tsig_keyname = strdup(src->_tsig_keyname)))) goto error_domain; if (dst->_tsig_keydata && (!(dst->_tsig_keydata = strdup(src->_tsig_keydata)))) goto error_tsig_keyname; if (dst->_tsig_algorithm && (!(dst->_tsig_algorithm = strdup(src->_tsig_algorithm)))) goto error_tsig_keydata; if (dst->_cur_axfr_pkt && (!(dst->_cur_axfr_pkt = ldns_pkt_clone(src->_cur_axfr_pkt)))) goto error_tsig_algorithm; if (dst->_dnssec_anchors && (!(dst->_dnssec_anchors=ldns_rr_list_clone(src->_dnssec_anchors)))) goto error_cur_axfr_pkt; return dst; error_cur_axfr_pkt: ldns_pkt_free(dst->_cur_axfr_pkt); error_tsig_algorithm: LDNS_FREE(dst->_tsig_algorithm); error_tsig_keydata: LDNS_FREE(dst->_tsig_keydata); error_tsig_keyname: LDNS_FREE(dst->_tsig_keyname); error_domain: ldns_rdf_deep_free(dst->_domain); error_rtt: LDNS_FREE(dst->_rtt); error_nameservers: for (i = 0; i < dst->_nameserver_count; i++) ldns_rdf_deep_free(dst->_nameservers[i]); LDNS_FREE(dst->_nameservers); error_searchlist: for (i = 0; i < dst->_searchlist_count; i++) ldns_rdf_deep_free(dst->_searchlist[i]); LDNS_FREE(dst->_searchlist); error: LDNS_FREE(dst); return NULL; } ldns_status ldns_resolver_new_frm_fp(ldns_resolver **res, FILE *fp) { return ldns_resolver_new_frm_fp_l(res, fp, NULL); } ldns_status ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) { ldns_resolver *r; const char *keyword[LDNS_RESOLV_KEYWORDS]; char word[LDNS_MAX_LINELEN + 1]; int8_t expect; uint8_t i; ldns_rdf *tmp; #ifdef HAVE_SSL ldns_rr *tmp_rr; #endif ssize_t gtr, bgtr; ldns_buffer *b; int lnr = 0, oldline; FILE* myfp = fp; if(!line_nr) line_nr = &lnr; if(!fp) { myfp = fopen("/etc/resolv.conf", "r"); if(!myfp) return LDNS_STATUS_FILE_ERR; } /* do this better * expect = * 0: keyword * 1: default domain dname * 2: NS aaaa or a record */ /* recognized keywords */ keyword[LDNS_RESOLV_NAMESERVER] = "nameserver"; keyword[LDNS_RESOLV_DEFDOMAIN] = "domain"; keyword[LDNS_RESOLV_SEARCH] = "search"; /* these two are read but not used atm TODO */ keyword[LDNS_RESOLV_SORTLIST] = "sortlist"; keyword[LDNS_RESOLV_OPTIONS] = "options"; keyword[LDNS_RESOLV_ANCHOR] = "anchor"; expect = LDNS_RESOLV_KEYWORD; r = ldns_resolver_new(); if (!r) { if(!fp) fclose(myfp); return LDNS_STATUS_MEM_ERR; } gtr = 1; word[0] = 0; oldline = *line_nr; expect = LDNS_RESOLV_KEYWORD; while (gtr > 0) { /* check comments */ if (word[0] == '#') { word[0]='x'; if(oldline == *line_nr) { /* skip until end of line */ int c; do { c = fgetc(myfp); } while(c != EOF && c != '\n'); if(c=='\n') (*line_nr)++; } /* and read next to prepare for further parsing */ oldline = *line_nr; continue; } oldline = *line_nr; switch(expect) { case LDNS_RESOLV_KEYWORD: /* keyword */ gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); if (gtr != 0) { if(word[0] == '#') continue; for(i = 0; i < LDNS_RESOLV_KEYWORDS; i++) { if (strcasecmp(keyword[i], word) == 0) { /* chosen the keyword and * expect values carefully */ expect = i; break; } } /* no keyword recognized */ if (expect == LDNS_RESOLV_KEYWORD) { /* skip line */ /* ldns_resolver_deep_free(r); if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_KEYWORD_ERR; */ } } break; case LDNS_RESOLV_DEFDOMAIN: /* default domain dname */ gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); if (gtr == 0) { if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; } if(word[0] == '#') { expect = LDNS_RESOLV_KEYWORD; continue; } tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word); if (!tmp) { ldns_resolver_deep_free(r); if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_DNAME_ERR; } /* DOn't free, because we copy the pointer */ ldns_resolver_set_domain(r, tmp); expect = LDNS_RESOLV_KEYWORD; break; case LDNS_RESOLV_NAMESERVER: /* NS aaaa or a record */ gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); if (gtr == 0) { if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; } if(word[0] == '#') { expect = LDNS_RESOLV_KEYWORD; continue; } if(strchr(word, '%')) { /* snip off interface labels, * fe80::222:19ff:fe31:4222%eth0 */ strchr(word, '%')[0]=0; } tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, word); if (!tmp) { /* try ip4 */ tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, word); } /* could not parse it, exit */ if (!tmp) { ldns_resolver_deep_free(r); if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_ERR; } (void)ldns_resolver_push_nameserver(r, tmp); ldns_rdf_deep_free(tmp); expect = LDNS_RESOLV_KEYWORD; break; case LDNS_RESOLV_SEARCH: /* search list domain dname */ gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); b = LDNS_MALLOC(ldns_buffer); if(!b) { ldns_resolver_deep_free(r); if(!fp) fclose(myfp); return LDNS_STATUS_MEM_ERR; } ldns_buffer_new_frm_data(b, word, (size_t) gtr); if(ldns_buffer_status(b) != LDNS_STATUS_OK) { LDNS_FREE(b); ldns_resolver_deep_free(r); if(!fp) fclose(myfp); return LDNS_STATUS_MEM_ERR; } bgtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL, (size_t) gtr + 1); while (bgtr > 0) { gtr -= bgtr; if(word[0] == '#') { expect = LDNS_RESOLV_KEYWORD; break; } tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word); if (!tmp) { ldns_resolver_deep_free(r); ldns_buffer_free(b); if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_DNAME_ERR; } ldns_resolver_push_searchlist(r, tmp); ldns_rdf_deep_free(tmp); bgtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL, (size_t) gtr + 1); } ldns_buffer_free(b); if (expect != LDNS_RESOLV_KEYWORD) { gtr = 1; expect = LDNS_RESOLV_KEYWORD; } break; case LDNS_RESOLV_SORTLIST: gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); /* sortlist not implemented atm */ expect = LDNS_RESOLV_KEYWORD; break; case LDNS_RESOLV_OPTIONS: gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); /* options not implemented atm */ expect = LDNS_RESOLV_KEYWORD; break; case LDNS_RESOLV_ANCHOR: /* a file containing a DNSSEC trust anchor */ gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); if (gtr == 0) { ldns_resolver_deep_free(r); if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; } if(word[0] == '#') { expect = LDNS_RESOLV_KEYWORD; continue; } #ifdef HAVE_SSL tmp_rr = ldns_read_anchor_file(word); (void) ldns_resolver_push_dnssec_anchor(r, tmp_rr); ldns_rr_free(tmp_rr); #endif expect = LDNS_RESOLV_KEYWORD; break; } } if(!fp) fclose(myfp); if (res) { *res = r; return LDNS_STATUS_OK; } else { ldns_resolver_deep_free(r); return LDNS_STATUS_NULL; } } ldns_status ldns_resolver_new_frm_file(ldns_resolver **res, const char *filename) { ldns_resolver *r; FILE *fp; ldns_status s; if (!filename) { fp = fopen(LDNS_RESOLV_CONF, "r"); } else { fp = fopen(filename, "r"); } if (!fp) { return LDNS_STATUS_FILE_ERR; } s = ldns_resolver_new_frm_fp(&r, fp); fclose(fp); if (s == LDNS_STATUS_OK) { if (res) { *res = r; return LDNS_STATUS_OK; } else { ldns_resolver_free(r); return LDNS_STATUS_NULL; } } return s; } void ldns_resolver_free(ldns_resolver *res) { LDNS_FREE(res); } void ldns_resolver_deep_free(ldns_resolver *res) { size_t i; if (res) { if (res->_searchlist) { for (i = 0; i < ldns_resolver_searchlist_count(res); i++) { ldns_rdf_deep_free(res->_searchlist[i]); } LDNS_FREE(res->_searchlist); } if (res->_nameservers) { for (i = 0; i < res->_nameserver_count; i++) { ldns_rdf_deep_free(res->_nameservers[i]); } LDNS_FREE(res->_nameservers); } if (ldns_resolver_domain(res)) { ldns_rdf_deep_free(ldns_resolver_domain(res)); } if (res->_tsig_keyname) { LDNS_FREE(res->_tsig_keyname); } if (res->_tsig_keydata) { LDNS_FREE(res->_tsig_keydata); } if (res->_tsig_algorithm) { LDNS_FREE(res->_tsig_algorithm); } if (res->_cur_axfr_pkt) { ldns_pkt_free(res->_cur_axfr_pkt); } if (res->_rtt) { LDNS_FREE(res->_rtt); } if (res->_dnssec_anchors) { ldns_rr_list_deep_free(res->_dnssec_anchors); } LDNS_FREE(res); } } ldns_status ldns_resolver_search_status(ldns_pkt** pkt, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags) { ldns_rdf *new_name; ldns_rdf **search_list; size_t i; ldns_status s = LDNS_STATUS_OK; ldns_rdf root_dname = { 1, LDNS_RDF_TYPE_DNAME, (void *)"" }; if (ldns_dname_absolute(name)) { /* query as-is */ return ldns_resolver_query_status(pkt, r, name, t, c, flags); } else if (ldns_resolver_dnsrch(r)) { search_list = ldns_resolver_searchlist(r); for (i = 0; i <= ldns_resolver_searchlist_count(r); i++) { if (i == ldns_resolver_searchlist_count(r)) { new_name = ldns_dname_cat_clone(name, &root_dname); } else { new_name = ldns_dname_cat_clone(name, search_list[i]); } s = ldns_resolver_query_status(pkt, r, new_name, t, c, flags); ldns_rdf_free(new_name); if (pkt && *pkt) { if (s == LDNS_STATUS_OK && ldns_pkt_get_rcode(*pkt) == LDNS_RCODE_NOERROR) { return LDNS_STATUS_OK; } ldns_pkt_free(*pkt); *pkt = NULL; } } } return s; } ldns_pkt * ldns_resolver_search(const ldns_resolver *r,const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags) { ldns_pkt* pkt = NULL; if (ldns_resolver_search_status(&pkt, (ldns_resolver *)r, name, t, c, flags) != LDNS_STATUS_OK) { ldns_pkt_free(pkt); } return pkt; } ldns_status ldns_resolver_query_status(ldns_pkt** pkt, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags) { ldns_rdf *newname; ldns_status status; if (!ldns_resolver_defnames(r) || !ldns_resolver_domain(r)) { return ldns_resolver_send(pkt, r, name, t, c, flags); } newname = ldns_dname_cat_clone(name, ldns_resolver_domain(r)); if (!newname) { return LDNS_STATUS_MEM_ERR; } status = ldns_resolver_send(pkt, r, newname, t, c, flags); ldns_rdf_free(newname); return status; } ldns_pkt * ldns_resolver_query(const ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags) { ldns_pkt* pkt = NULL; if (ldns_resolver_query_status(&pkt, (ldns_resolver *)r, name, t, c, flags) != LDNS_STATUS_OK) { ldns_pkt_free(pkt); } return pkt; } static size_t * ldns_resolver_backup_rtt(ldns_resolver *r) { size_t *new_rtt; size_t *old_rtt = ldns_resolver_rtt(r); if (old_rtt && ldns_resolver_nameserver_count(r)) { new_rtt = LDNS_XMALLOC(size_t , ldns_resolver_nameserver_count(r)); memcpy(new_rtt, old_rtt, sizeof(size_t) * ldns_resolver_nameserver_count(r)); ldns_resolver_set_rtt(r, new_rtt); return old_rtt; } return NULL; } static void ldns_resolver_restore_rtt(ldns_resolver *r, size_t *old_rtt) { size_t *cur_rtt = ldns_resolver_rtt(r); if (cur_rtt) { LDNS_FREE(cur_rtt); } ldns_resolver_set_rtt(r, old_rtt); } ldns_status ldns_resolver_send_pkt(ldns_pkt **answer, ldns_resolver *r, ldns_pkt *query_pkt) { ldns_pkt *answer_pkt = NULL; ldns_status stat = LDNS_STATUS_OK; size_t *rtt; stat = ldns_send(&answer_pkt, (ldns_resolver *)r, query_pkt); if (stat != LDNS_STATUS_OK) { if(answer_pkt) { ldns_pkt_free(answer_pkt); answer_pkt = NULL; } } else { /* if tc=1 fall back to EDNS and/or TCP */ /* check for tcp first (otherwise we don't care about tc=1) */ if (!ldns_resolver_usevc(r) && ldns_resolver_fallback(r)) { if (ldns_pkt_tc(answer_pkt)) { /* was EDNS0 set? */ if (ldns_pkt_edns_udp_size(query_pkt) == 0) { ldns_pkt_set_edns_udp_size(query_pkt , 4096); ldns_pkt_free(answer_pkt); answer_pkt = NULL; /* Nameservers should not become * unreachable because fragments are * dropped (network error). We might * still have success with TCP. * Therefore maintain reachability * statuses of the nameservers by * backup and restore the rtt list. */ rtt = ldns_resolver_backup_rtt(r); stat = ldns_send(&answer_pkt, r , query_pkt); ldns_resolver_restore_rtt(r, rtt); } /* either way, if it is still truncated, use TCP */ if (stat != LDNS_STATUS_OK || ldns_pkt_tc(answer_pkt)) { ldns_resolver_set_usevc(r, true); ldns_pkt_free(answer_pkt); stat = ldns_send(&answer_pkt, r, query_pkt); ldns_resolver_set_usevc(r, false); } } } } if (answer) { *answer = answer_pkt; } return stat; } ldns_status ldns_resolver_prepare_query_pkt(ldns_pkt **query_pkt, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags) { struct timeval now; ldns_rr* soa = NULL; /* prepare a question pkt from the parameters * and then send this */ if (t == LDNS_RR_TYPE_IXFR) { ldns_rdf *owner_rdf; ldns_rdf *mname_rdf; ldns_rdf *rname_rdf; ldns_rdf *serial_rdf; ldns_rdf *refresh_rdf; ldns_rdf *retry_rdf; ldns_rdf *expire_rdf; ldns_rdf *minimum_rdf; soa = ldns_rr_new(); if (!soa) { return LDNS_STATUS_ERR; } owner_rdf = ldns_rdf_clone(name); if (!owner_rdf) { ldns_rr_free(soa); return LDNS_STATUS_ERR; } ldns_rr_set_owner(soa, owner_rdf); ldns_rr_set_type(soa, LDNS_RR_TYPE_SOA); ldns_rr_set_class(soa, c); ldns_rr_set_question(soa, false); if (ldns_str2rdf_dname(&mname_rdf, ".") != LDNS_STATUS_OK) { ldns_rr_free(soa); return LDNS_STATUS_ERR; } else ldns_rr_push_rdf(soa, mname_rdf); if (ldns_str2rdf_dname(&rname_rdf, ".") != LDNS_STATUS_OK) { ldns_rr_free(soa); return LDNS_STATUS_ERR; } else ldns_rr_push_rdf(soa, rname_rdf); serial_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, ldns_resolver_get_ixfr_serial(r)); if (!serial_rdf) { ldns_rr_free(soa); return LDNS_STATUS_ERR; } else ldns_rr_push_rdf(soa, serial_rdf); refresh_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!refresh_rdf) { ldns_rr_free(soa); return LDNS_STATUS_ERR; } else ldns_rr_push_rdf(soa, refresh_rdf); retry_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!retry_rdf) { ldns_rr_free(soa); return LDNS_STATUS_ERR; } else ldns_rr_push_rdf(soa, retry_rdf); expire_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!expire_rdf) { ldns_rr_free(soa); return LDNS_STATUS_ERR; } else ldns_rr_push_rdf(soa, expire_rdf); minimum_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!minimum_rdf) { ldns_rr_free(soa); return LDNS_STATUS_ERR; } else ldns_rr_push_rdf(soa, minimum_rdf); *query_pkt = ldns_pkt_ixfr_request_new(ldns_rdf_clone(name), c, flags, soa); } else { *query_pkt = ldns_pkt_query_new(ldns_rdf_clone(name), t, c, flags); } if (!*query_pkt) { ldns_rr_free(soa); return LDNS_STATUS_ERR; } /* set DO bit if necessary */ if (ldns_resolver_dnssec(r)) { if (ldns_resolver_edns_udp_size(r) == 0) { ldns_resolver_set_edns_udp_size(r, 4096); } ldns_pkt_set_edns_do(*query_pkt, true); if (ldns_resolver_dnssec_cd(r) || (flags & LDNS_CD)) { ldns_pkt_set_cd(*query_pkt, true); } } /* transfer the udp_edns_size from the resolver to the packet */ if (ldns_resolver_edns_udp_size(r) != 0) { ldns_pkt_set_edns_udp_size(*query_pkt, ldns_resolver_edns_udp_size(r)); } /* set the timestamp */ now.tv_sec = time(NULL); now.tv_usec = 0; ldns_pkt_set_timestamp(*query_pkt, now); if (ldns_resolver_debug(r)) { ldns_pkt_print(stdout, *query_pkt); } /* only set the id if it is not set yet */ if (ldns_pkt_id(*query_pkt) == 0) { ldns_pkt_set_random_id(*query_pkt); } return LDNS_STATUS_OK; } ldns_status ldns_resolver_send(ldns_pkt **answer, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags) { ldns_pkt *query_pkt; ldns_pkt *answer_pkt; ldns_status status; assert(r != NULL); assert(name != NULL); answer_pkt = NULL; /* do all the preprocessing here, then fire of an query to * the network */ if (0 == t) { t= LDNS_RR_TYPE_A; } if (0 == c) { c= LDNS_RR_CLASS_IN; } if (0 == ldns_resolver_nameserver_count(r)) { return LDNS_STATUS_RES_NO_NS; } if (ldns_rdf_get_type(name) != LDNS_RDF_TYPE_DNAME) { return LDNS_STATUS_RES_QUERY; } status = ldns_resolver_prepare_query_pkt(&query_pkt, r, name, t, c, flags); if (status != LDNS_STATUS_OK) { return status; } /* if tsig values are set, tsign it */ /* TODO: make last 3 arguments optional too? maybe make complete rr instead of separate values in resolver (and packet) Jelte should this go in pkt_prepare? */ if (ldns_resolver_tsig_keyname(r) && ldns_resolver_tsig_keydata(r)) { #ifdef HAVE_SSL status = ldns_pkt_tsig_sign(query_pkt, ldns_resolver_tsig_keyname(r), ldns_resolver_tsig_keydata(r), 300, ldns_resolver_tsig_algorithm(r), NULL); if (status != LDNS_STATUS_OK) { ldns_pkt_free(query_pkt); return LDNS_STATUS_CRYPTO_TSIG_ERR; } #else ldns_pkt_free(query_pkt); return LDNS_STATUS_CRYPTO_TSIG_ERR; #endif /* HAVE_SSL */ } status = ldns_resolver_send_pkt(&answer_pkt, r, query_pkt); ldns_pkt_free(query_pkt); /* allows answer to be NULL when not interested in return value */ if (answer) { *answer = answer_pkt; } return status; } ldns_rr * ldns_axfr_next(ldns_resolver *resolver) { ldns_rr *cur_rr; uint8_t *packet_wire; size_t packet_wire_size; ldns_status status; /* check if start() has been called */ if (!resolver || resolver->_socket == 0) { return NULL; } if (resolver->_cur_axfr_pkt) { if (resolver->_axfr_i == ldns_pkt_ancount(resolver->_cur_axfr_pkt)) { ldns_pkt_free(resolver->_cur_axfr_pkt); resolver->_cur_axfr_pkt = NULL; return ldns_axfr_next(resolver); } cur_rr = ldns_rr_clone(ldns_rr_list_rr( ldns_pkt_answer(resolver->_cur_axfr_pkt), resolver->_axfr_i)); resolver->_axfr_i++; if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SOA) { resolver->_axfr_soa_count++; if (resolver->_axfr_soa_count >= 2) { #ifndef USE_WINSOCK close(resolver->_socket); #else closesocket(resolver->_socket); #endif resolver->_socket = 0; ldns_pkt_free(resolver->_cur_axfr_pkt); resolver->_cur_axfr_pkt = NULL; } } return cur_rr; } else { packet_wire = ldns_tcp_read_wire_timeout(resolver->_socket, &packet_wire_size, resolver->_timeout); if(!packet_wire) return NULL; status = ldns_wire2pkt(&resolver->_cur_axfr_pkt, packet_wire, packet_wire_size); LDNS_FREE(packet_wire); resolver->_axfr_i = 0; if (status != LDNS_STATUS_OK) { /* TODO: make status return type of this function (...api change) */ #ifdef STDERR_MSGS fprintf(stderr, "Error parsing rr during AXFR: %s\n", ldns_get_errorstr_by_id(status)); #endif /* we must now also close the socket, otherwise subsequent uses of the same resolver structure will fail because the link is still open or in an undefined state */ #ifndef USE_WINSOCK close(resolver->_socket); #else closesocket(resolver->_socket); #endif resolver->_socket = 0; return NULL; } else if (ldns_pkt_get_rcode(resolver->_cur_axfr_pkt) != 0) { #ifdef STDERR_MSGS ldns_lookup_table *rcode = ldns_lookup_by_id( ldns_rcodes,(int) ldns_pkt_get_rcode( resolver->_cur_axfr_pkt)); if (rcode) { fprintf(stderr, "Error in AXFR: %s\n", rcode->name); } else { fprintf(stderr, "Error in AXFR: %d\n", (int) ldns_pkt_get_rcode( resolver->_cur_axfr_pkt)); } #endif /* we must now also close the socket, otherwise subsequent uses of the same resolver structure will fail because the link is still open or in an undefined state */ #ifndef USE_WINSOCK close(resolver->_socket); #else closesocket(resolver->_socket); #endif resolver->_socket = 0; return NULL; } else { return ldns_axfr_next(resolver); } } } /* this function is needed to abort a transfer that is in progress; * without it an aborted transfer will lead to the AXFR code in the * library staying in an indetermined state because the socket for the * AXFR is never closed */ void ldns_axfr_abort(ldns_resolver *resolver) { /* Only abort if an actual AXFR is in progress */ if (resolver->_socket != 0) { #ifndef USE_WINSOCK close(resolver->_socket); #else closesocket(resolver->_socket); #endif resolver->_socket = 0; } } bool ldns_axfr_complete(const ldns_resolver *res) { /* complete when soa count is 2? */ return res->_axfr_soa_count == 2; } ldns_pkt * ldns_axfr_last_pkt(const ldns_resolver *res) { return res->_cur_axfr_pkt; } void ldns_resolver_set_ixfr_serial(ldns_resolver *r, uint32_t serial) { r->_serial = serial; } uint32_t ldns_resolver_get_ixfr_serial(const ldns_resolver *res) { return res->_serial; } /* random isn't really that good */ void ldns_resolver_nameservers_randomize(ldns_resolver *r) { uint16_t i, j; ldns_rdf **ns, *tmpns; size_t *rtt, tmprtt; /* should I check for ldns_resolver_random?? */ assert(r != NULL); ns = ldns_resolver_nameservers(r); rtt = ldns_resolver_rtt(r); for (i = 0; i < ldns_resolver_nameserver_count(r); i++) { j = ldns_get_random() % ldns_resolver_nameserver_count(r); tmpns = ns[i]; ns[i] = ns[j]; ns[j] = tmpns; tmprtt = rtt[i]; rtt[i] = rtt[j]; rtt[j] = tmprtt; } ldns_resolver_set_nameservers(r, ns); } Net-LDNS-0.75/src/ldns/rr.c000644 000770 000024 00000246720 12471046240 015645 0ustar00calledstaff000000 000000 /* rr.c * * access functions for ldns_rr - * a Net::DNS like library for C * LibDNS Team @ NLnet Labs * * (c) NLnet Labs, 2004-2006 * See the file LICENSE for the license */ #include #include #include #include #include #define LDNS_SYNTAX_DATALEN 16 #define LDNS_TTL_DATALEN 21 #define LDNS_RRLIST_INIT 8 ldns_rr * ldns_rr_new(void) { ldns_rr *rr; rr = LDNS_MALLOC(ldns_rr); if (!rr) { return NULL; } ldns_rr_set_owner(rr, NULL); ldns_rr_set_question(rr, false); ldns_rr_set_rd_count(rr, 0); rr->_rdata_fields = NULL; ldns_rr_set_class(rr, LDNS_RR_CLASS_IN); ldns_rr_set_ttl(rr, LDNS_DEFAULT_TTL); return rr; } ldns_rr * ldns_rr_new_frm_type(ldns_rr_type t) { ldns_rr *rr; const ldns_rr_descriptor *desc; size_t i; rr = LDNS_MALLOC(ldns_rr); if (!rr) { return NULL; } desc = ldns_rr_descript(t); rr->_rdata_fields = LDNS_XMALLOC(ldns_rdf *, ldns_rr_descriptor_minimum(desc)); if(!rr->_rdata_fields) { LDNS_FREE(rr); return NULL; } for (i = 0; i < ldns_rr_descriptor_minimum(desc); i++) { rr->_rdata_fields[i] = NULL; } ldns_rr_set_owner(rr, NULL); ldns_rr_set_question(rr, false); /* set the count to minimum */ ldns_rr_set_rd_count(rr, ldns_rr_descriptor_minimum(desc)); ldns_rr_set_class(rr, LDNS_RR_CLASS_IN); ldns_rr_set_ttl(rr, LDNS_DEFAULT_TTL); ldns_rr_set_type(rr, t); return rr; } void ldns_rr_free(ldns_rr *rr) { size_t i; if (rr) { if (ldns_rr_owner(rr)) { ldns_rdf_deep_free(ldns_rr_owner(rr)); } for (i = 0; i < ldns_rr_rd_count(rr); i++) { ldns_rdf_deep_free(ldns_rr_rdf(rr, i)); } LDNS_FREE(rr->_rdata_fields); LDNS_FREE(rr); } } /* Syntactic sugar for ldns_rr_new_frm_str_internal */ INLINE bool ldns_rdf_type_maybe_quoted(ldns_rdf_type rdf_type) { return rdf_type == LDNS_RDF_TYPE_STR || rdf_type == LDNS_RDF_TYPE_LONG_STR; } /* * trailing spaces are allowed * leading spaces are not allowed * allow ttl to be optional * class is optional too * if ttl is missing, and default_ttl is 0, use DEF_TTL * allow ttl to be written as 1d3h * So the RR should look like. e.g. * miek.nl. 3600 IN MX 10 elektron.atoom.net * or * miek.nl. 1h IN MX 10 elektron.atoom.net * or * miek.nl. IN MX 10 elektron.atoom.net */ static ldns_status ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, uint32_t default_ttl, ldns_rdf *origin, ldns_rdf **prev, bool question) { ldns_rr *new; const ldns_rr_descriptor *desc; ldns_rr_type rr_type; ldns_buffer *rr_buf = NULL; ldns_buffer *rd_buf = NULL; uint32_t ttl_val; char *owner = NULL; char *ttl = NULL; ldns_rr_class clas_val; char *clas = NULL; char *type = NULL; char *rdata = NULL; char *rd = NULL; char *xtok = NULL; /* For RDF types with spaces (i.e. extra tokens) */ size_t rd_strlen; const char *delimiters; ssize_t c; ldns_rdf *owner_dname; const char* endptr; int was_unknown_rr_format = 0; ldns_status status = LDNS_STATUS_OK; /* used for types with unknown number of rdatas */ bool done; bool quoted; ldns_rdf *r = NULL; uint16_t r_cnt; uint16_t r_min; uint16_t r_max; size_t pre_data_pos; uint16_t hex_data_size; char *hex_data_str = NULL; uint16_t cur_hex_data_size; size_t hex_pos = 0; uint8_t *hex_data = NULL; new = ldns_rr_new(); owner = LDNS_XMALLOC(char, LDNS_MAX_DOMAINLEN + 1); ttl = LDNS_XMALLOC(char, LDNS_TTL_DATALEN); clas = LDNS_XMALLOC(char, LDNS_SYNTAX_DATALEN); rdata = LDNS_XMALLOC(char, LDNS_MAX_PACKETLEN + 1); rr_buf = LDNS_MALLOC(ldns_buffer); rd_buf = LDNS_MALLOC(ldns_buffer); rd = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN); xtok = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN); if (rr_buf) { rr_buf->_data = NULL; } if (rd_buf) { rd_buf->_data = NULL; } if (!new || !owner || !ttl || !clas || !rdata || !rr_buf || !rd_buf || !rd || !xtok) { goto memerror; } ldns_buffer_new_frm_data(rr_buf, (char*)str, strlen(str)); /* split the rr in its parts -1 signals trouble */ if (ldns_bget_token(rr_buf, owner, "\t\n ", LDNS_MAX_DOMAINLEN) == -1){ status = LDNS_STATUS_SYNTAX_ERR; goto error; } if (ldns_bget_token(rr_buf, ttl, "\t\n ", LDNS_TTL_DATALEN) == -1) { status = LDNS_STATUS_SYNTAX_TTL_ERR; goto error; } ttl_val = (uint32_t) ldns_str2period(ttl, &endptr); if (strlen(ttl) > 0 && !isdigit((int) ttl[0])) { /* ah, it's not there or something */ if (default_ttl == 0) { ttl_val = LDNS_DEFAULT_TTL; } else { ttl_val = default_ttl; } /* we not ASSUMING the TTL is missing and that * the rest of the RR is still there. That is * CLASS TYPE RDATA * so ttl value we read is actually the class */ clas_val = ldns_get_rr_class_by_name(ttl); /* class can be left out too, assume IN, current * token must be type */ if (clas_val == 0) { clas_val = LDNS_RR_CLASS_IN; type = LDNS_XMALLOC(char, strlen(ttl) + 1); if (!type) { goto memerror; } strncpy(type, ttl, strlen(ttl) + 1); } } else { if (-1 == ldns_bget_token( rr_buf, clas, "\t\n ", LDNS_SYNTAX_DATALEN)) { status = LDNS_STATUS_SYNTAX_CLASS_ERR; goto error; } clas_val = ldns_get_rr_class_by_name(clas); /* class can be left out too, assume IN, current * token must be type */ if (clas_val == 0) { clas_val = LDNS_RR_CLASS_IN; type = LDNS_XMALLOC(char, strlen(clas) + 1); if (!type) { goto memerror; } strncpy(type, clas, strlen(clas) + 1); } } /* the rest should still be waiting for us */ if (!type) { type = LDNS_XMALLOC(char, LDNS_SYNTAX_DATALEN); if (!type) { goto memerror; } if (-1 == ldns_bget_token( rr_buf, type, "\t\n ", LDNS_SYNTAX_DATALEN)) { status = LDNS_STATUS_SYNTAX_TYPE_ERR; goto error; } } if (ldns_bget_token(rr_buf, rdata, "\0", LDNS_MAX_PACKETLEN) == -1) { /* apparently we are done, and it's only a question RR * so do not set status and go to ldnserror here */ } ldns_buffer_new_frm_data(rd_buf, rdata, strlen(rdata)); if (strlen(owner) <= 1 && strncmp(owner, "@", 1) == 0) { if (origin) { ldns_rr_set_owner(new, ldns_rdf_clone(origin)); } else if (prev && *prev) { ldns_rr_set_owner(new, ldns_rdf_clone(*prev)); } else { /* default to root */ ldns_rr_set_owner(new, ldns_dname_new_frm_str(".")); } /* @ also overrides prev */ if (prev) { ldns_rdf_deep_free(*prev); *prev = ldns_rdf_clone(ldns_rr_owner(new)); if (!*prev) { goto memerror; } } } else { if (strlen(owner) == 0) { /* no ownername was given, try prev, if that fails * origin, else default to root */ if (prev && *prev) { ldns_rr_set_owner(new, ldns_rdf_clone(*prev)); } else if (origin) { ldns_rr_set_owner(new, ldns_rdf_clone(origin)); } else { ldns_rr_set_owner(new, ldns_dname_new_frm_str(".")); } if(!ldns_rr_owner(new)) { goto memerror; } } else { owner_dname = ldns_dname_new_frm_str(owner); if (!owner_dname) { status = LDNS_STATUS_SYNTAX_ERR; goto error; } ldns_rr_set_owner(new, owner_dname); if (!ldns_dname_str_absolute(owner) && origin) { if(ldns_dname_cat(ldns_rr_owner(new), origin) != LDNS_STATUS_OK) { status = LDNS_STATUS_SYNTAX_ERR; goto error; } } if (prev) { ldns_rdf_deep_free(*prev); *prev = ldns_rdf_clone(ldns_rr_owner(new)); if (!*prev) { goto error; } } } } LDNS_FREE(owner); ldns_rr_set_question(new, question); ldns_rr_set_ttl(new, ttl_val); LDNS_FREE(ttl); ldns_rr_set_class(new, clas_val); LDNS_FREE(clas); rr_type = ldns_get_rr_type_by_name(type); LDNS_FREE(type); desc = ldns_rr_descript((uint16_t)rr_type); ldns_rr_set_type(new, rr_type); if (desc) { /* only the rdata remains */ r_max = ldns_rr_descriptor_maximum(desc); r_min = ldns_rr_descriptor_minimum(desc); } else { r_min = 0; r_max = 1; } for (done = false, r_cnt = 0; !done && r_cnt < r_max; r_cnt++) { quoted = false; switch (ldns_rr_descriptor_field_type(desc, r_cnt)) { case LDNS_RDF_TYPE_B64 : case LDNS_RDF_TYPE_HEX : /* These rdf types may con- */ case LDNS_RDF_TYPE_LOC : /* tain whitespace, only if */ case LDNS_RDF_TYPE_WKS : /* it is the last rd field. */ case LDNS_RDF_TYPE_IPSECKEY : case LDNS_RDF_TYPE_NSEC : if (r_cnt == r_max - 1) { delimiters = "\n"; break; } default : delimiters = "\n\t "; } if (ldns_rdf_type_maybe_quoted( ldns_rr_descriptor_field_type( desc, r_cnt)) && ldns_buffer_remaining(rd_buf) > 0){ /* skip spaces */ while (*(ldns_buffer_current(rd_buf)) == ' ') { ldns_buffer_skip(rd_buf, 1); } if (*(ldns_buffer_current(rd_buf)) == '\"') { delimiters = "\"\0"; ldns_buffer_skip(rd_buf, 1); quoted = true; } } /* because number of fields can be variable, we can't rely on * _maximum() only */ /* skip spaces */ while (ldns_buffer_position(rd_buf) < ldns_buffer_limit(rd_buf) && *(ldns_buffer_current(rd_buf)) == ' ' && !quoted) { ldns_buffer_skip(rd_buf, 1); } pre_data_pos = ldns_buffer_position(rd_buf); if (-1 == (c = ldns_bget_token( rd_buf, rd, delimiters, LDNS_MAX_RDFLEN))) { done = true; break; } /* hmmz, rfc3597 specifies that any type can be represented * with \# method, which can contain spaces... * it does specify size though... */ rd_strlen = strlen(rd); /* unknown RR data */ if (strncmp(rd, "\\#", 2) == 0 && !quoted && (rd_strlen == 2 || rd[2]==' ')) { was_unknown_rr_format = 1; /* go back to before \# * and skip it while setting delimiters better */ ldns_buffer_set_position(rd_buf, pre_data_pos); delimiters = "\n\t "; (void)ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN); /* read rdata octet length */ c = ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN); if (c == -1) { /* something goes very wrong here */ status = LDNS_STATUS_SYNTAX_RDATA_ERR; goto error; } hex_data_size = (uint16_t) atoi(rd); /* copy hex chars into hex str (2 chars per byte) */ hex_data_str = LDNS_XMALLOC(char, 2*hex_data_size + 1); if (!hex_data_str) { /* malloc error */ goto memerror; } cur_hex_data_size = 0; while(cur_hex_data_size < 2 * hex_data_size) { c = ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN); if (c != -1) { rd_strlen = strlen(rd); } if (c == -1 || (size_t)cur_hex_data_size + rd_strlen > 2 * (size_t)hex_data_size) { status = LDNS_STATUS_SYNTAX_RDATA_ERR; goto error; } strncpy(hex_data_str + cur_hex_data_size, rd, rd_strlen); cur_hex_data_size += rd_strlen; } hex_data_str[cur_hex_data_size] = '\0'; /* correct the rdf type */ /* if *we* know the type, interpret it as wireformat */ if (desc) { hex_pos = 0; hex_data = LDNS_XMALLOC(uint8_t, hex_data_size+2); if (!hex_data) { goto memerror; } ldns_write_uint16(hex_data, hex_data_size); ldns_hexstring_to_data( hex_data + 2, hex_data_str); status = ldns_wire2rdf(new, hex_data, hex_data_size + 2, &hex_pos); if (status != LDNS_STATUS_OK) { goto error; } LDNS_FREE(hex_data); } else { r = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_HEX, hex_data_str); if (!r) { goto memerror; } ldns_rdf_set_type(r, LDNS_RDF_TYPE_UNKNOWN); if (!ldns_rr_push_rdf(new, r)) { goto memerror; } } LDNS_FREE(hex_data_str); } else if(rd_strlen > 0 || quoted) { /* Normal RR */ switch(ldns_rr_descriptor_field_type(desc, r_cnt)) { case LDNS_RDF_TYPE_HEX: case LDNS_RDF_TYPE_B64: /* When this is the last rdata field, then the * rest should be read in (cause then these * rdf types may contain spaces). */ if (r_cnt == r_max - 1) { c = ldns_bget_token(rd_buf, xtok, "\n", LDNS_MAX_RDFLEN); if (c != -1) { (void) strncat(rd, xtok, LDNS_MAX_RDFLEN - strlen(rd) - 1); } } r = ldns_rdf_new_frm_str( ldns_rr_descriptor_field_type( desc, r_cnt), rd); break; case LDNS_RDF_TYPE_HIP: /* * In presentation format this RDATA type has * three tokens: An algorithm byte, then a * variable length HIT (in hexbytes) and then * a variable length Public Key (in base64). * * We have just read the algorithm, so we need * two more tokens: HIT and Public Key. */ do { /* Read and append HIT */ if (ldns_bget_token(rd_buf, xtok, delimiters, LDNS_MAX_RDFLEN) == -1) break; (void) strncat(rd, " ", LDNS_MAX_RDFLEN - strlen(rd) - 1); (void) strncat(rd, xtok, LDNS_MAX_RDFLEN - strlen(rd) - 1); /* Read and append Public Key*/ if (ldns_bget_token(rd_buf, xtok, delimiters, LDNS_MAX_RDFLEN) == -1) break; (void) strncat(rd, " ", LDNS_MAX_RDFLEN - strlen(rd) - 1); (void) strncat(rd, xtok, LDNS_MAX_RDFLEN - strlen(rd) - 1); } while (false); r = ldns_rdf_new_frm_str( ldns_rr_descriptor_field_type( desc, r_cnt), rd); break; case LDNS_RDF_TYPE_DNAME: r = ldns_rdf_new_frm_str( ldns_rr_descriptor_field_type( desc, r_cnt), rd); /* check if the origin should be used * or concatenated */ if (r && ldns_rdf_size(r) > 1 && ldns_rdf_data(r)[0] == 1 && ldns_rdf_data(r)[1] == '@') { ldns_rdf_deep_free(r); r = origin ? ldns_rdf_clone(origin) : ( rr_type == LDNS_RR_TYPE_SOA ? ldns_rdf_clone( ldns_rr_owner(new)) : ldns_rdf_new_frm_str( LDNS_RDF_TYPE_DNAME, ".") ); } else if (r && rd_strlen >= 1 && origin && !ldns_dname_str_absolute(rd)) { status = ldns_dname_cat(r, origin); if (status != LDNS_STATUS_OK) { goto error; } } break; default: r = ldns_rdf_new_frm_str( ldns_rr_descriptor_field_type( desc, r_cnt), rd); break; } if (!r) { status = LDNS_STATUS_SYNTAX_RDATA_ERR; goto error; } ldns_rr_push_rdf(new, r); } if (quoted) { if (ldns_buffer_available(rd_buf, 1)) { ldns_buffer_skip(rd_buf, 1); } else { done = true; } } } /* for (done = false, r_cnt = 0; !done && r_cnt < r_max; r_cnt++) */ LDNS_FREE(rd); LDNS_FREE(xtok); ldns_buffer_free(rd_buf); ldns_buffer_free(rr_buf); LDNS_FREE(rdata); if (!question && desc && !was_unknown_rr_format && ldns_rr_rd_count(new) < r_min) { ldns_rr_free(new); return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; } if (newrr) { *newrr = new; } else { /* Maybe the caller just wanted to see if it would parse? */ ldns_rr_free(new); } return LDNS_STATUS_OK; memerror: status = LDNS_STATUS_MEM_ERR; error: if (rd_buf && rd_buf->_data) { ldns_buffer_free(rd_buf); } else { LDNS_FREE(rd_buf); } if (rr_buf && rr_buf->_data) { ldns_buffer_free(rr_buf); } else { LDNS_FREE(rr_buf); } LDNS_FREE(type); LDNS_FREE(owner); LDNS_FREE(ttl); LDNS_FREE(clas); LDNS_FREE(hex_data); LDNS_FREE(hex_data_str); LDNS_FREE(xtok); LDNS_FREE(rd); LDNS_FREE(rdata); ldns_rr_free(new); return status; } ldns_status ldns_rr_new_frm_str(ldns_rr **newrr, const char *str, uint32_t default_ttl, ldns_rdf *origin, ldns_rdf **prev) { return ldns_rr_new_frm_str_internal(newrr, str, default_ttl, origin, prev, false); } ldns_status ldns_rr_new_question_frm_str(ldns_rr **newrr, const char *str, ldns_rdf *origin, ldns_rdf **prev) { return ldns_rr_new_frm_str_internal(newrr, str, 0, origin, prev, true); } /* Strip whitespace from the start and the end of . */ static char * ldns_strip_ws(char *line) { char *s = line, *e; for (s = line; *s && isspace(*s); s++) ; for (e = strchr(s, 0); e > s+2 && isspace(e[-1]) && e[-2] != '\\'; e--) ; *e = 0; return s; } ldns_status ldns_rr_new_frm_fp(ldns_rr **newrr, FILE *fp, uint32_t *ttl, ldns_rdf **origin, ldns_rdf **prev) { return ldns_rr_new_frm_fp_l(newrr, fp, ttl, origin, prev, NULL); } ldns_status ldns_rr_new_frm_fp_l(ldns_rr **newrr, FILE *fp, uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev, int *line_nr) { char *line; const char *endptr; /* unused */ ldns_rr *rr; uint32_t ttl; ldns_rdf *tmp; ldns_status s; ssize_t size; if (default_ttl) { ttl = *default_ttl; } else { ttl = 0; } line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1); if (!line) { return LDNS_STATUS_MEM_ERR; } /* read an entire line in from the file */ if ((size = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, LDNS_MAX_LINELEN, line_nr)) == -1) { LDNS_FREE(line); /* if last line was empty, we are now at feof, which is not * always a parse error (happens when for instance last line * was a comment) */ return LDNS_STATUS_SYNTAX_ERR; } /* we can have the situation, where we've read ok, but still got * no bytes to play with, in this case size is 0 */ if (size == 0) { LDNS_FREE(line); return LDNS_STATUS_SYNTAX_EMPTY; } if (strncmp(line, "$ORIGIN", 7) == 0 && isspace(line[7])) { if (*origin) { ldns_rdf_deep_free(*origin); *origin = NULL; } tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, ldns_strip_ws(line + 8)); if (!tmp) { /* could not parse what next to $ORIGIN */ LDNS_FREE(line); return LDNS_STATUS_SYNTAX_DNAME_ERR; } *origin = tmp; s = LDNS_STATUS_SYNTAX_ORIGIN; } else if (strncmp(line, "$TTL", 4) == 0 && isspace(line[4])) { if (default_ttl) { *default_ttl = ldns_str2period( ldns_strip_ws(line + 5), &endptr); } s = LDNS_STATUS_SYNTAX_TTL; } else if (strncmp(line, "$INCLUDE", 8) == 0) { s = LDNS_STATUS_SYNTAX_INCLUDE; } else if (!*ldns_strip_ws(line)) { LDNS_FREE(line); return LDNS_STATUS_SYNTAX_EMPTY; } else { if (origin && *origin) { s = ldns_rr_new_frm_str(&rr, (const char*) line, ttl, *origin, prev); } else { s = ldns_rr_new_frm_str(&rr, (const char*) line, ttl, NULL, prev); } } LDNS_FREE(line); if (s == LDNS_STATUS_OK) { if (newrr) { *newrr = rr; } else { /* Just testing if it would parse? */ ldns_rr_free(rr); } } return s; } void ldns_rr_set_owner(ldns_rr *rr, ldns_rdf *owner) { rr->_owner = owner; } void ldns_rr_set_question(ldns_rr *rr, bool question) { rr->_rr_question = question; } void ldns_rr_set_ttl(ldns_rr *rr, uint32_t ttl) { rr->_ttl = ttl; } void ldns_rr_set_rd_count(ldns_rr *rr, size_t count) { rr->_rd_count = count; } void ldns_rr_set_type(ldns_rr *rr, ldns_rr_type rr_type) { rr->_rr_type = rr_type; } void ldns_rr_set_class(ldns_rr *rr, ldns_rr_class rr_class) { rr->_rr_class = rr_class; } ldns_rdf * ldns_rr_set_rdf(ldns_rr *rr, const ldns_rdf *f, size_t position) { size_t rd_count; ldns_rdf *pop; rd_count = ldns_rr_rd_count(rr); if (position < rd_count) { /* dicard the old one */ pop = rr->_rdata_fields[position]; rr->_rdata_fields[position] = (ldns_rdf*)f; return pop; } else { return NULL; } } bool ldns_rr_push_rdf(ldns_rr *rr, const ldns_rdf *f) { size_t rd_count; ldns_rdf **rdata_fields; rd_count = ldns_rr_rd_count(rr); /* grow the array */ rdata_fields = LDNS_XREALLOC( rr->_rdata_fields, ldns_rdf *, rd_count + 1); if (!rdata_fields) { return false; } /* add the new member */ rr->_rdata_fields = rdata_fields; rr->_rdata_fields[rd_count] = (ldns_rdf*)f; ldns_rr_set_rd_count(rr, rd_count + 1); return true; } ldns_rdf * ldns_rr_pop_rdf(ldns_rr *rr) { size_t rd_count; ldns_rdf *pop; ldns_rdf** newrd; rd_count = ldns_rr_rd_count(rr); if (rd_count == 0) { return NULL; } pop = rr->_rdata_fields[rd_count - 1]; /* try to shrink the array */ if(rd_count > 1) { newrd = LDNS_XREALLOC( rr->_rdata_fields, ldns_rdf *, rd_count - 1); if(newrd) rr->_rdata_fields = newrd; } else { LDNS_FREE(rr->_rdata_fields); } ldns_rr_set_rd_count(rr, rd_count - 1); return pop; } ldns_rdf * ldns_rr_rdf(const ldns_rr *rr, size_t nr) { if (rr && nr < ldns_rr_rd_count(rr)) { return rr->_rdata_fields[nr]; } else { return NULL; } } ldns_rdf * ldns_rr_owner(const ldns_rr *rr) { return rr->_owner; } bool ldns_rr_is_question(const ldns_rr *rr) { return rr->_rr_question; } uint32_t ldns_rr_ttl(const ldns_rr *rr) { return rr->_ttl; } size_t ldns_rr_rd_count(const ldns_rr *rr) { return rr->_rd_count; } ldns_rr_type ldns_rr_get_type(const ldns_rr *rr) { return rr->_rr_type; } ldns_rr_class ldns_rr_get_class(const ldns_rr *rr) { return rr->_rr_class; } /* rr_lists */ size_t ldns_rr_list_rr_count(const ldns_rr_list *rr_list) { if (rr_list) { return rr_list->_rr_count; } else { return 0; } } ldns_rr * ldns_rr_list_set_rr(ldns_rr_list *rr_list, const ldns_rr *r, size_t count) { ldns_rr *old; if (count > ldns_rr_list_rr_count(rr_list)) { return NULL; } old = ldns_rr_list_rr(rr_list, count); /* overwrite old's pointer */ rr_list->_rrs[count] = (ldns_rr*)r; return old; } void ldns_rr_list_set_rr_count(ldns_rr_list *rr_list, size_t count) { assert(count <= rr_list->_rr_capacity); rr_list->_rr_count = count; } ldns_rr * ldns_rr_list_rr(const ldns_rr_list *rr_list, size_t nr) { if (nr < ldns_rr_list_rr_count(rr_list)) { return rr_list->_rrs[nr]; } else { return NULL; } } ldns_rr_list * ldns_rr_list_new(void) { ldns_rr_list *rr_list = LDNS_MALLOC(ldns_rr_list); if(!rr_list) return NULL; rr_list->_rr_count = 0; rr_list->_rr_capacity = 0; rr_list->_rrs = NULL; return rr_list; } void ldns_rr_list_free(ldns_rr_list *rr_list) { if (rr_list) { LDNS_FREE(rr_list->_rrs); LDNS_FREE(rr_list); } } void ldns_rr_list_deep_free(ldns_rr_list *rr_list) { size_t i; if (rr_list) { for (i=0; i < ldns_rr_list_rr_count(rr_list); i++) { ldns_rr_free(ldns_rr_list_rr(rr_list, i)); } LDNS_FREE(rr_list->_rrs); LDNS_FREE(rr_list); } } /* add right to left. So we modify *left! */ bool ldns_rr_list_cat(ldns_rr_list *left, ldns_rr_list *right) { size_t r_rr_count; size_t i; if (!left) { return false; } if (right) { r_rr_count = ldns_rr_list_rr_count(right); } else { r_rr_count = 0; } /* push right to left */ for(i = 0; i < r_rr_count; i++) { ldns_rr_list_push_rr(left, ldns_rr_list_rr(right, i)); } return true; } ldns_rr_list * ldns_rr_list_cat_clone(ldns_rr_list *left, ldns_rr_list *right) { size_t l_rr_count; size_t r_rr_count; size_t i; ldns_rr_list *cat; if (left) { l_rr_count = ldns_rr_list_rr_count(left); } else { return ldns_rr_list_clone(right); } if (right) { r_rr_count = ldns_rr_list_rr_count(right); } else { r_rr_count = 0; } cat = ldns_rr_list_new(); if (!cat) { return NULL; } /* left */ for(i = 0; i < l_rr_count; i++) { ldns_rr_list_push_rr(cat, ldns_rr_clone(ldns_rr_list_rr(left, i))); } /* right */ for(i = 0; i < r_rr_count; i++) { ldns_rr_list_push_rr(cat, ldns_rr_clone(ldns_rr_list_rr(right, i))); } return cat; } ldns_rr_list * ldns_rr_list_subtype_by_rdf(ldns_rr_list *l, ldns_rdf *r, size_t pos) { size_t i; ldns_rr_list *subtyped; ldns_rdf *list_rdf; subtyped = ldns_rr_list_new(); for(i = 0; i < ldns_rr_list_rr_count(l); i++) { list_rdf = ldns_rr_rdf( ldns_rr_list_rr(l, i), pos); if (!list_rdf) { /* pos is too large or any other error */ ldns_rr_list_deep_free(subtyped); return NULL; } if (ldns_rdf_compare(list_rdf, r) == 0) { /* a match */ ldns_rr_list_push_rr(subtyped, ldns_rr_clone(ldns_rr_list_rr(l, i))); } } if (ldns_rr_list_rr_count(subtyped) > 0) { return subtyped; } else { ldns_rr_list_free(subtyped); return NULL; } } bool ldns_rr_list_push_rr(ldns_rr_list *rr_list, const ldns_rr *rr) { size_t rr_count; size_t cap; rr_count = ldns_rr_list_rr_count(rr_list); cap = rr_list->_rr_capacity; /* grow the array */ if(rr_count+1 > cap) { ldns_rr **rrs; if(cap == 0) cap = LDNS_RRLIST_INIT; /* initial list size */ else cap *= 2; rrs = LDNS_XREALLOC(rr_list->_rrs, ldns_rr *, cap); if (!rrs) { return false; } rr_list->_rrs = rrs; rr_list->_rr_capacity = cap; } /* add the new member */ rr_list->_rrs[rr_count] = (ldns_rr*)rr; ldns_rr_list_set_rr_count(rr_list, rr_count + 1); return true; } bool ldns_rr_list_push_rr_list(ldns_rr_list *rr_list, const ldns_rr_list *push_list) { size_t i; for(i = 0; i < ldns_rr_list_rr_count(push_list); i++) { if (!ldns_rr_list_push_rr(rr_list, ldns_rr_list_rr(push_list, i))) { return false; } } return true; } ldns_rr * ldns_rr_list_pop_rr(ldns_rr_list *rr_list) { size_t rr_count; size_t cap; ldns_rr *pop; rr_count = ldns_rr_list_rr_count(rr_list); if (rr_count == 0) { return NULL; } cap = rr_list->_rr_capacity; pop = ldns_rr_list_rr(rr_list, rr_count - 1); /* shrink the array */ if(cap > LDNS_RRLIST_INIT && rr_count-1 <= cap/2) { ldns_rr** a; cap /= 2; a = LDNS_XREALLOC(rr_list->_rrs, ldns_rr *, cap); if(a) { rr_list->_rrs = a; rr_list->_rr_capacity = cap; } } ldns_rr_list_set_rr_count(rr_list, rr_count - 1); return pop; } ldns_rr_list * ldns_rr_list_pop_rr_list(ldns_rr_list *rr_list, size_t howmany) { /* pop a number of rr's and put them in a rr_list */ ldns_rr_list *popped; ldns_rr *p; size_t i = howmany; popped = ldns_rr_list_new(); if (!popped) { return NULL; } while(i > 0 && (p = ldns_rr_list_pop_rr(rr_list)) != NULL) { ldns_rr_list_push_rr(popped, p); i--; } if (i == howmany) { /* so i <= 0 */ ldns_rr_list_free(popped); return NULL; } else { return popped; } } bool ldns_rr_list_contains_rr(const ldns_rr_list *rr_list, ldns_rr *rr) { size_t i; if (!rr_list || !rr || ldns_rr_list_rr_count(rr_list) == 0) { return false; } for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { if (rr == ldns_rr_list_rr(rr_list, i)) { return true; } else if (ldns_rr_compare(rr, ldns_rr_list_rr(rr_list, i)) == 0) { return true; } } return false; } bool ldns_is_rrset(ldns_rr_list *rr_list) { ldns_rr_type t; ldns_rr_class c; ldns_rdf *o; ldns_rr *tmp; size_t i; if (!rr_list || ldns_rr_list_rr_count(rr_list) == 0) { return false; } tmp = ldns_rr_list_rr(rr_list, 0); t = ldns_rr_get_type(tmp); c = ldns_rr_get_class(tmp); o = ldns_rr_owner(tmp); /* compare these with the rest of the rr_list, start with 1 */ for (i = 1; i < ldns_rr_list_rr_count(rr_list); i++) { tmp = ldns_rr_list_rr(rr_list, i); if (t != ldns_rr_get_type(tmp)) { return false; } if (c != ldns_rr_get_class(tmp)) { return false; } if (ldns_rdf_compare(o, ldns_rr_owner(tmp)) != 0) { return false; } } return true; } bool ldns_rr_set_push_rr(ldns_rr_list *rr_list, ldns_rr *rr) { size_t rr_count; size_t i; ldns_rr *last; assert(rr != NULL); rr_count = ldns_rr_list_rr_count(rr_list); if (rr_count == 0) { /* nothing there, so checking it is * not needed */ return ldns_rr_list_push_rr(rr_list, rr); } else { /* check with the final rr in the rr_list */ last = ldns_rr_list_rr(rr_list, rr_count - 1); if (ldns_rr_get_class(last) != ldns_rr_get_class(rr)) { return false; } if (ldns_rr_get_type(last) != ldns_rr_get_type(rr)) { return false; } /* only check if not equal to RRSIG */ if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) { if (ldns_rr_ttl(last) != ldns_rr_ttl(rr)) { return false; } } if (ldns_rdf_compare(ldns_rr_owner(last), ldns_rr_owner(rr)) != 0) { return false; } /* ok, still alive - check if the rr already * exists - if so, dont' add it */ for(i = 0; i < rr_count; i++) { if(ldns_rr_compare( ldns_rr_list_rr(rr_list, i), rr) == 0) { return false; } } /* it's safe, push it */ return ldns_rr_list_push_rr(rr_list, rr); } } ldns_rr * ldns_rr_set_pop_rr(ldns_rr_list *rr_list) { return ldns_rr_list_pop_rr(rr_list); } ldns_rr_list * ldns_rr_list_pop_rrset(ldns_rr_list *rr_list) { ldns_rr_list *rrset; ldns_rr *last_rr = NULL; ldns_rr *next_rr; if (!rr_list) { return NULL; } rrset = ldns_rr_list_new(); if (!last_rr) { last_rr = ldns_rr_list_pop_rr(rr_list); if (!last_rr) { ldns_rr_list_free(rrset); return NULL; } else { ldns_rr_list_push_rr(rrset, last_rr); } } if (ldns_rr_list_rr_count(rr_list) > 0) { next_rr = ldns_rr_list_rr(rr_list, ldns_rr_list_rr_count(rr_list) - 1); } else { next_rr = NULL; } while (next_rr) { if ( ldns_rdf_compare(ldns_rr_owner(next_rr), ldns_rr_owner(last_rr)) == 0 && ldns_rr_get_type(next_rr) == ldns_rr_get_type(last_rr) && ldns_rr_get_class(next_rr) == ldns_rr_get_class(last_rr) ) { ldns_rr_list_push_rr(rrset, ldns_rr_list_pop_rr(rr_list)); if (ldns_rr_list_rr_count(rr_list) > 0) { last_rr = next_rr; next_rr = ldns_rr_list_rr(rr_list, ldns_rr_list_rr_count(rr_list) - 1); } else { next_rr = NULL; } } else { next_rr = NULL; } } return rrset; } ldns_rr * ldns_rr_clone(const ldns_rr *rr) { size_t i; ldns_rr *new_rr; if (!rr) { return NULL; } new_rr = ldns_rr_new(); if (!new_rr) { return NULL; } if (ldns_rr_owner(rr)) { ldns_rr_set_owner(new_rr, ldns_rdf_clone(ldns_rr_owner(rr))); } ldns_rr_set_ttl(new_rr, ldns_rr_ttl(rr)); ldns_rr_set_type(new_rr, ldns_rr_get_type(rr)); ldns_rr_set_class(new_rr, ldns_rr_get_class(rr)); ldns_rr_set_question(new_rr, ldns_rr_is_question(rr)); for (i = 0; i < ldns_rr_rd_count(rr); i++) { if (ldns_rr_rdf(rr,i)) { ldns_rr_push_rdf(new_rr, ldns_rdf_clone(ldns_rr_rdf(rr, i))); } } return new_rr; } ldns_rr_list * ldns_rr_list_clone(const ldns_rr_list *rrlist) { size_t i; ldns_rr_list *new_list; ldns_rr *r; if (!rrlist) { return NULL; } new_list = ldns_rr_list_new(); if (!new_list) { return NULL; } for (i = 0; i < ldns_rr_list_rr_count(rrlist); i++) { r = ldns_rr_clone( ldns_rr_list_rr(rrlist, i) ); if (!r) { /* huh, failure in cloning */ ldns_rr_list_deep_free(new_list); return NULL; } ldns_rr_list_push_rr(new_list, r); } return new_list; } static int qsort_schwartz_rr_compare(const void *a, const void *b) { int result = 0; ldns_rr *rr1, *rr2; ldns_buffer *rr1_buf, *rr2_buf; struct ldns_schwartzian_compare_struct *sa = *(struct ldns_schwartzian_compare_struct **) a; struct ldns_schwartzian_compare_struct *sb = *(struct ldns_schwartzian_compare_struct **) b; /* if we are doing 2wire, we need to do lowercasing on the dname (and maybe on the rdata) * this must be done for comparison only, so we need to have a temp var for both buffers, * which is only used when the transformed object value isn't there yet */ ldns_rr *canonical_a, *canonical_b; rr1 = (ldns_rr *) sa->original_object; rr2 = (ldns_rr *) sb->original_object; result = ldns_rr_compare_no_rdata(rr1, rr2); if (result == 0) { if (!sa->transformed_object) { canonical_a = ldns_rr_clone(sa->original_object); ldns_rr2canonical(canonical_a); sa->transformed_object = ldns_buffer_new(ldns_rr_uncompressed_size(canonical_a)); if (ldns_rr2buffer_wire(sa->transformed_object, canonical_a, LDNS_SECTION_ANY) != LDNS_STATUS_OK) { ldns_buffer_free((ldns_buffer *)sa->transformed_object); sa->transformed_object = NULL; ldns_rr_free(canonical_a); return 0; } ldns_rr_free(canonical_a); } if (!sb->transformed_object) { canonical_b = ldns_rr_clone(sb->original_object); ldns_rr2canonical(canonical_b); sb->transformed_object = ldns_buffer_new(ldns_rr_uncompressed_size(canonical_b)); if (ldns_rr2buffer_wire(sb->transformed_object, canonical_b, LDNS_SECTION_ANY) != LDNS_STATUS_OK) { ldns_buffer_free((ldns_buffer *)sa->transformed_object); ldns_buffer_free((ldns_buffer *)sb->transformed_object); sa->transformed_object = NULL; sb->transformed_object = NULL; ldns_rr_free(canonical_b); return 0; } ldns_rr_free(canonical_b); } rr1_buf = (ldns_buffer *) sa->transformed_object; rr2_buf = (ldns_buffer *) sb->transformed_object; result = ldns_rr_compare_wire(rr1_buf, rr2_buf); } return result; } void ldns_rr_list_sort(ldns_rr_list *unsorted) { struct ldns_schwartzian_compare_struct **sortables; size_t item_count; size_t i; if (unsorted) { item_count = ldns_rr_list_rr_count(unsorted); sortables = LDNS_XMALLOC(struct ldns_schwartzian_compare_struct *, item_count); if(!sortables) return; /* no way to return error */ for (i = 0; i < item_count; i++) { sortables[i] = LDNS_XMALLOC(struct ldns_schwartzian_compare_struct, 1); if(!sortables[i]) { /* free the allocated parts */ while(i>0) { i--; LDNS_FREE(sortables[i]); } /* no way to return error */ LDNS_FREE(sortables); return; } sortables[i]->original_object = ldns_rr_list_rr(unsorted, i); sortables[i]->transformed_object = NULL; } qsort(sortables, item_count, sizeof(struct ldns_schwartzian_compare_struct *), qsort_schwartz_rr_compare); for (i = 0; i < item_count; i++) { unsorted->_rrs[i] = sortables[i]->original_object; if (sortables[i]->transformed_object) { ldns_buffer_free(sortables[i]->transformed_object); } LDNS_FREE(sortables[i]); } LDNS_FREE(sortables); } } int ldns_rr_compare_no_rdata(const ldns_rr *rr1, const ldns_rr *rr2) { size_t rr1_len; size_t rr2_len; size_t offset; assert(rr1 != NULL); assert(rr2 != NULL); rr1_len = ldns_rr_uncompressed_size(rr1); rr2_len = ldns_rr_uncompressed_size(rr2); if (ldns_dname_compare(ldns_rr_owner(rr1), ldns_rr_owner(rr2)) < 0) { return -1; } else if (ldns_dname_compare(ldns_rr_owner(rr1), ldns_rr_owner(rr2)) > 0) { return 1; } /* should return -1 if rr1 comes before rr2, so need to do rr1 - rr2, not rr2 - rr1 */ if (ldns_rr_get_class(rr1) != ldns_rr_get_class(rr2)) { return ldns_rr_get_class(rr1) - ldns_rr_get_class(rr2); } /* should return -1 if rr1 comes before rr2, so need to do rr1 - rr2, not rr2 - rr1 */ if (ldns_rr_get_type(rr1) != ldns_rr_get_type(rr2)) { return ldns_rr_get_type(rr1) - ldns_rr_get_type(rr2); } /* offset is the owername length + ttl + type + class + rdlen == start of wire format rdata */ offset = ldns_rdf_size(ldns_rr_owner(rr1)) + 4 + 2 + 2 + 2; /* if either record doesn't have any RDATA... */ if (offset > rr1_len || offset > rr2_len) { if (rr1_len == rr2_len) { return 0; } return ((int) rr2_len - (int) rr1_len); } return 0; } int ldns_rr_compare_wire(ldns_buffer *rr1_buf, ldns_buffer *rr2_buf) { size_t rr1_len, rr2_len, min_len, i, offset; rr1_len = ldns_buffer_capacity(rr1_buf); rr2_len = ldns_buffer_capacity(rr2_buf); /* jump past dname (checked in earlier part) * and especially past TTL */ offset = 0; while (offset < rr1_len && *ldns_buffer_at(rr1_buf, offset) != 0) { offset += *ldns_buffer_at(rr1_buf, offset) + 1; } /* jump to rdata section (PAST the rdata length field, otherwise rrs with different lengths might be sorted erroneously */ offset += 11; min_len = (rr1_len < rr2_len) ? rr1_len : rr2_len; /* Compare RRs RDATA byte for byte. */ for(i = offset; i < min_len; i++) { if (*ldns_buffer_at(rr1_buf,i) < *ldns_buffer_at(rr2_buf,i)) { return -1; } else if (*ldns_buffer_at(rr1_buf,i) > *ldns_buffer_at(rr2_buf,i)) { return +1; } } /* If both RDATAs are the same up to min_len, then the shorter one sorts first. */ if (rr1_len < rr2_len) { return -1; } else if (rr1_len > rr2_len) { return +1; } /* The RDATAs are equal. */ return 0; } int ldns_rr_compare(const ldns_rr *rr1, const ldns_rr *rr2) { int result; size_t rr1_len, rr2_len; ldns_buffer *rr1_buf; ldns_buffer *rr2_buf; result = ldns_rr_compare_no_rdata(rr1, rr2); if (result == 0) { rr1_len = ldns_rr_uncompressed_size(rr1); rr2_len = ldns_rr_uncompressed_size(rr2); rr1_buf = ldns_buffer_new(rr1_len); rr2_buf = ldns_buffer_new(rr2_len); if (ldns_rr2buffer_wire_canonical(rr1_buf, rr1, LDNS_SECTION_ANY) != LDNS_STATUS_OK) { ldns_buffer_free(rr1_buf); ldns_buffer_free(rr2_buf); return 0; } if (ldns_rr2buffer_wire_canonical(rr2_buf, rr2, LDNS_SECTION_ANY) != LDNS_STATUS_OK) { ldns_buffer_free(rr1_buf); ldns_buffer_free(rr2_buf); return 0; } result = ldns_rr_compare_wire(rr1_buf, rr2_buf); ldns_buffer_free(rr1_buf); ldns_buffer_free(rr2_buf); } return result; } /* convert dnskey to a ds with the given algorithm, * then compare the result with the given ds */ static int ldns_rr_compare_ds_dnskey(ldns_rr *ds, ldns_rr *dnskey) { ldns_rr *ds_gen; bool result = false; ldns_hash algo; if (!dnskey || !ds || ldns_rr_get_type(ds) != LDNS_RR_TYPE_DS || ldns_rr_get_type(dnskey) != LDNS_RR_TYPE_DNSKEY) { return false; } if (ldns_rr_rdf(ds, 2) == NULL) { return false; } algo = ldns_rdf2native_int8(ldns_rr_rdf(ds, 2)); ds_gen = ldns_key_rr2ds(dnskey, algo); if (ds_gen) { result = ldns_rr_compare(ds, ds_gen) == 0; ldns_rr_free(ds_gen); } return result; } bool ldns_rr_compare_ds(const ldns_rr *orr1, const ldns_rr *orr2) { bool result; ldns_rr *rr1 = ldns_rr_clone(orr1); ldns_rr *rr2 = ldns_rr_clone(orr2); /* set ttls to zero */ ldns_rr_set_ttl(rr1, 0); ldns_rr_set_ttl(rr2, 0); if (ldns_rr_get_type(rr1) == LDNS_RR_TYPE_DS && ldns_rr_get_type(rr2) == LDNS_RR_TYPE_DNSKEY) { result = ldns_rr_compare_ds_dnskey(rr1, rr2); } else if (ldns_rr_get_type(rr1) == LDNS_RR_TYPE_DNSKEY && ldns_rr_get_type(rr2) == LDNS_RR_TYPE_DS) { result = ldns_rr_compare_ds_dnskey(rr2, rr1); } else { result = (ldns_rr_compare(rr1, rr2) == 0); } ldns_rr_free(rr1); ldns_rr_free(rr2); return result; } int ldns_rr_list_compare(const ldns_rr_list *rrl1, const ldns_rr_list *rrl2) { size_t i = 0; int rr_cmp; assert(rrl1 != NULL); assert(rrl2 != NULL); for (i = 0; i < ldns_rr_list_rr_count(rrl1) && i < ldns_rr_list_rr_count(rrl2); i++) { rr_cmp = ldns_rr_compare(ldns_rr_list_rr(rrl1, i), ldns_rr_list_rr(rrl2, i)); if (rr_cmp != 0) { return rr_cmp; } } if (i == ldns_rr_list_rr_count(rrl1) && i != ldns_rr_list_rr_count(rrl2)) { return 1; } else if (i == ldns_rr_list_rr_count(rrl2) && i != ldns_rr_list_rr_count(rrl1)) { return -1; } else { return 0; } } size_t ldns_rr_uncompressed_size(const ldns_rr *r) { size_t rrsize; size_t i; rrsize = 0; /* add all the rdf sizes */ for(i = 0; i < ldns_rr_rd_count(r); i++) { rrsize += ldns_rdf_size(ldns_rr_rdf(r, i)); } /* ownername */ rrsize += ldns_rdf_size(ldns_rr_owner(r)); rrsize += LDNS_RR_OVERHEAD; return rrsize; } void ldns_rr2canonical(ldns_rr *rr) { uint16_t i; if (!rr) { return; } ldns_dname2canonical(ldns_rr_owner(rr)); /* * lowercase the rdata dnames if the rr type is one * of the list in chapter 7 of RFC3597 * Also added RRSIG, because a "Signer's Name" should be canonicalized * too. See dnssec-bis-updates-16. We can add it to this list because * the "Signer's Name" is the only dname type rdata field in a RRSIG. */ switch(ldns_rr_get_type(rr)) { case LDNS_RR_TYPE_NS: case LDNS_RR_TYPE_MD: case LDNS_RR_TYPE_MF: case LDNS_RR_TYPE_CNAME: case LDNS_RR_TYPE_SOA: case LDNS_RR_TYPE_MB: case LDNS_RR_TYPE_MG: case LDNS_RR_TYPE_MR: case LDNS_RR_TYPE_PTR: case LDNS_RR_TYPE_MINFO: case LDNS_RR_TYPE_MX: case LDNS_RR_TYPE_RP: case LDNS_RR_TYPE_AFSDB: case LDNS_RR_TYPE_RT: case LDNS_RR_TYPE_SIG: case LDNS_RR_TYPE_PX: case LDNS_RR_TYPE_NXT: case LDNS_RR_TYPE_NAPTR: case LDNS_RR_TYPE_KX: case LDNS_RR_TYPE_SRV: case LDNS_RR_TYPE_DNAME: case LDNS_RR_TYPE_A6: case LDNS_RR_TYPE_RRSIG: for (i = 0; i < ldns_rr_rd_count(rr); i++) { ldns_dname2canonical(ldns_rr_rdf(rr, i)); } return; default: /* do nothing */ return; } } void ldns_rr_list2canonical(ldns_rr_list *rr_list) { size_t i; for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { ldns_rr2canonical(ldns_rr_list_rr(rr_list, i)); } } uint8_t ldns_rr_label_count(ldns_rr *rr) { if (!rr) { return 0; } return ldns_dname_label_count( ldns_rr_owner(rr)); } /** \cond */ static const ldns_rdf_type type_0_wireformat[] = { LDNS_RDF_TYPE_UNKNOWN }; static const ldns_rdf_type type_a_wireformat[] = { LDNS_RDF_TYPE_A }; static const ldns_rdf_type type_ns_wireformat[] = { LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_md_wireformat[] = { LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_mf_wireformat[] = { LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_cname_wireformat[] = { LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_soa_wireformat[] = { LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_INT32, LDNS_RDF_TYPE_PERIOD, LDNS_RDF_TYPE_PERIOD, LDNS_RDF_TYPE_PERIOD, LDNS_RDF_TYPE_PERIOD }; static const ldns_rdf_type type_mb_wireformat[] = { LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_mg_wireformat[] = { LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_mr_wireformat[] = { LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_wks_wireformat[] = { LDNS_RDF_TYPE_A, LDNS_RDF_TYPE_WKS }; static const ldns_rdf_type type_ptr_wireformat[] = { LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_hinfo_wireformat[] = { LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR }; static const ldns_rdf_type type_minfo_wireformat[] = { LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_mx_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_rp_wireformat[] = { LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_afsdb_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_x25_wireformat[] = { LDNS_RDF_TYPE_STR }; static const ldns_rdf_type type_isdn_wireformat[] = { LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR }; static const ldns_rdf_type type_rt_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_nsap_wireformat[] = { LDNS_RDF_TYPE_NSAP }; static const ldns_rdf_type type_nsap_ptr_wireformat[] = { LDNS_RDF_TYPE_STR }; static const ldns_rdf_type type_sig_wireformat[] = { LDNS_RDF_TYPE_TYPE, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT32, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_B64 }; static const ldns_rdf_type type_key_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_B64 }; static const ldns_rdf_type type_px_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_gpos_wireformat[] = { LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR }; static const ldns_rdf_type type_aaaa_wireformat[] = { LDNS_RDF_TYPE_AAAA }; static const ldns_rdf_type type_loc_wireformat[] = { LDNS_RDF_TYPE_LOC }; static const ldns_rdf_type type_nxt_wireformat[] = { LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_UNKNOWN }; static const ldns_rdf_type type_eid_wireformat[] = { LDNS_RDF_TYPE_HEX }; static const ldns_rdf_type type_nimloc_wireformat[] = { LDNS_RDF_TYPE_HEX }; static const ldns_rdf_type type_srv_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_atma_wireformat[] = { LDNS_RDF_TYPE_ATMA }; static const ldns_rdf_type type_naptr_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_kx_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_cert_wireformat[] = { LDNS_RDF_TYPE_CERT_ALG, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_B64 }; static const ldns_rdf_type type_a6_wireformat[] = { LDNS_RDF_TYPE_UNKNOWN }; static const ldns_rdf_type type_dname_wireformat[] = { LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_sink_wireformat[] = { LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_B64 }; static const ldns_rdf_type type_apl_wireformat[] = { LDNS_RDF_TYPE_APL }; static const ldns_rdf_type type_ds_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX }; static const ldns_rdf_type type_sshfp_wireformat[] = { LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX }; static const ldns_rdf_type type_ipseckey_wireformat[] = { LDNS_RDF_TYPE_IPSECKEY }; static const ldns_rdf_type type_rrsig_wireformat[] = { LDNS_RDF_TYPE_TYPE, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT32, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_B64 }; static const ldns_rdf_type type_nsec_wireformat[] = { LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_NSEC }; static const ldns_rdf_type type_dhcid_wireformat[] = { LDNS_RDF_TYPE_B64 }; static const ldns_rdf_type type_talink_wireformat[] = { LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME }; /*@unused@*/ static const ldns_rdf_type type_openpgpkey_wireformat[] = { LDNS_RDF_TYPE_B64 }; /* nsec3 is some vars, followed by same type of data of nsec */ static const ldns_rdf_type type_nsec3_wireformat[] = { /* LDNS_RDF_TYPE_NSEC3_VARS, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC*/ LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_NSEC3_SALT, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC }; static const ldns_rdf_type type_nsec3param_wireformat[] = { /* LDNS_RDF_TYPE_NSEC3_PARAMS_VARS*/ LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_NSEC3_SALT }; static const ldns_rdf_type type_dnskey_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_B64 }; static const ldns_rdf_type type_tkey_wireformat[] = { LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16_DATA, LDNS_RDF_TYPE_INT16_DATA, }; static const ldns_rdf_type type_tsig_wireformat[] = { LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_TSIGTIME, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16_DATA, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16_DATA }; static const ldns_rdf_type type_tlsa_wireformat[] = { LDNS_RDF_TYPE_CERTIFICATE_USAGE, LDNS_RDF_TYPE_SELECTOR, LDNS_RDF_TYPE_MATCHING_TYPE, LDNS_RDF_TYPE_HEX }; static const ldns_rdf_type type_hip_wireformat[] = { LDNS_RDF_TYPE_HIP }; static const ldns_rdf_type type_nid_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ILNP64 }; static const ldns_rdf_type type_l32_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_A }; static const ldns_rdf_type type_l64_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ILNP64 }; static const ldns_rdf_type type_lp_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_eui48_wireformat[] = { LDNS_RDF_TYPE_EUI48 }; static const ldns_rdf_type type_eui64_wireformat[] = { LDNS_RDF_TYPE_EUI64 }; #ifdef RRTYPE_URI static const ldns_rdf_type type_uri_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_LONG_STR }; #endif static const ldns_rdf_type type_caa_wireformat[] = { LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_TAG, LDNS_RDF_TYPE_LONG_STR }; /** \endcond */ /** \cond */ /* All RR's defined in 1035 are well known and can thus * be compressed. See RFC3597. These RR's are: * CNAME HINFO MB MD MF MG MINFO MR MX NULL NS PTR SOA TXT */ static ldns_rr_descriptor rdata_field_descriptors[] = { /* 0 */ { 0, NULL, 0, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 1 */ {LDNS_RR_TYPE_A, "A", 1, 1, type_a_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 2 */ {LDNS_RR_TYPE_NS, "NS", 1, 1, type_ns_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 }, /* 3 */ {LDNS_RR_TYPE_MD, "MD", 1, 1, type_md_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 }, /* 4 */ {LDNS_RR_TYPE_MF, "MF", 1, 1, type_mf_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 }, /* 5 */ {LDNS_RR_TYPE_CNAME, "CNAME", 1, 1, type_cname_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 }, /* 6 */ {LDNS_RR_TYPE_SOA, "SOA", 7, 7, type_soa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 2 }, /* 7 */ {LDNS_RR_TYPE_MB, "MB", 1, 1, type_mb_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 }, /* 8 */ {LDNS_RR_TYPE_MG, "MG", 1, 1, type_mg_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 }, /* 9 */ {LDNS_RR_TYPE_MR, "MR", 1, 1, type_mr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 }, /* 10 */ {LDNS_RR_TYPE_NULL, "NULL", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 11 */ {LDNS_RR_TYPE_WKS, "WKS", 2, 2, type_wks_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 12 */ {LDNS_RR_TYPE_PTR, "PTR", 1, 1, type_ptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 }, /* 13 */ {LDNS_RR_TYPE_HINFO, "HINFO", 2, 2, type_hinfo_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 14 */ {LDNS_RR_TYPE_MINFO, "MINFO", 2, 2, type_minfo_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 2 }, /* 15 */ {LDNS_RR_TYPE_MX, "MX", 2, 2, type_mx_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 }, /* 16 */ {LDNS_RR_TYPE_TXT, "TXT", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 }, /* 17 */ {LDNS_RR_TYPE_RP, "RP", 2, 2, type_rp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 }, /* 18 */ {LDNS_RR_TYPE_AFSDB, "AFSDB", 2, 2, type_afsdb_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 19 */ {LDNS_RR_TYPE_X25, "X25", 1, 1, type_x25_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 20 */ {LDNS_RR_TYPE_ISDN, "ISDN", 1, 2, type_isdn_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 21 */ {LDNS_RR_TYPE_RT, "RT", 2, 2, type_rt_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 22 */ {LDNS_RR_TYPE_NSAP, "NSAP", 1, 1, type_nsap_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 23 */ {LDNS_RR_TYPE_NSAP_PTR, "NSAP-PTR", 1, 1, type_nsap_ptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 24 */ {LDNS_RR_TYPE_SIG, "SIG", 9, 9, type_sig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 25 */ {LDNS_RR_TYPE_KEY, "KEY", 4, 4, type_key_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 26 */ {LDNS_RR_TYPE_PX, "PX", 3, 3, type_px_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 }, /* 27 */ {LDNS_RR_TYPE_GPOS, "GPOS", 3, 3, type_gpos_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 28 */ {LDNS_RR_TYPE_AAAA, "AAAA", 1, 1, type_aaaa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 29 */ {LDNS_RR_TYPE_LOC, "LOC", 1, 1, type_loc_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 30 */ {LDNS_RR_TYPE_NXT, "NXT", 2, 2, type_nxt_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 31 */ {LDNS_RR_TYPE_EID, "EID", 1, 1, type_eid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 32 */ {LDNS_RR_TYPE_NIMLOC, "NIMLOC", 1, 1, type_nimloc_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 33 */ {LDNS_RR_TYPE_SRV, "SRV", 4, 4, type_srv_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 34 */ {LDNS_RR_TYPE_ATMA, "ATMA", 1, 1, type_atma_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 35 */ {LDNS_RR_TYPE_NAPTR, "NAPTR", 6, 6, type_naptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 36 */ {LDNS_RR_TYPE_KX, "KX", 2, 2, type_kx_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 37 */ {LDNS_RR_TYPE_CERT, "CERT", 4, 4, type_cert_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 38 */ {LDNS_RR_TYPE_A6, "A6", 1, 1, type_a6_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 39 */ {LDNS_RR_TYPE_DNAME, "DNAME", 1, 1, type_dname_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 40 */ {LDNS_RR_TYPE_SINK, "SINK", 1, 1, type_sink_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 41 */ {LDNS_RR_TYPE_OPT, "OPT", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 42 */ {LDNS_RR_TYPE_APL, "APL", 0, 0, type_apl_wireformat, LDNS_RDF_TYPE_APL, LDNS_RR_NO_COMPRESS, 0 }, /* 43 */ {LDNS_RR_TYPE_DS, "DS", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 44 */ {LDNS_RR_TYPE_SSHFP, "SSHFP", 3, 3, type_sshfp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 45 */ {LDNS_RR_TYPE_IPSECKEY, "IPSECKEY", 1, 1, type_ipseckey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 46 */ {LDNS_RR_TYPE_RRSIG, "RRSIG", 9, 9, type_rrsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 47 */ {LDNS_RR_TYPE_NSEC, "NSEC", 1, 2, type_nsec_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 48 */ {LDNS_RR_TYPE_DNSKEY, "DNSKEY", 4, 4, type_dnskey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 49 */ {LDNS_RR_TYPE_DHCID, "DHCID", 1, 1, type_dhcid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 50 */ {LDNS_RR_TYPE_NSEC3, "NSEC3", 5, 6, type_nsec3_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 51 */ {LDNS_RR_TYPE_NSEC3PARAM, "NSEC3PARAM", 4, 4, type_nsec3param_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 52 */ {LDNS_RR_TYPE_TLSA, "TLSA", 4, 4, type_tlsa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE53", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE54", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 55 * Hip ends with 0 or more Rendezvous Servers represented as dname's. * Hence the LDNS_RDF_TYPE_DNAME _variable field and the _maximum field * set to 0. */ {LDNS_RR_TYPE_HIP, "HIP", 1, 1, type_hip_wireformat, LDNS_RDF_TYPE_DNAME, LDNS_RR_NO_COMPRESS, 0 }, #ifdef RRTYPE_NINFO /* 56 */ {LDNS_RR_TYPE_NINFO, "NINFO", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 }, #else {LDNS_RR_TYPE_NULL, "TYPE56", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #endif #ifdef RRTYPE_RKEY /* 57 */ {LDNS_RR_TYPE_RKEY, "RKEY", 4, 4, type_key_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #else {LDNS_RR_TYPE_NULL, "TYPE57", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #endif /* 58 */ {LDNS_RR_TYPE_TALINK, "TALINK", 2, 2, type_talink_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 }, /* 59 */ {LDNS_RR_TYPE_CDS, "CDS", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 60 */ {LDNS_RR_TYPE_CDNSKEY, "CDNSKEY", 4, 4, type_dnskey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #ifdef RRTYPE_OPENPGPKEY /* 61 */ {LDNS_RR_TYPE_OPENPGPKEY, "OPENPGPKEY", 1, 1, type_openpgpkey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #else {LDNS_RR_TYPE_NULL, "TYPE61", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #endif {LDNS_RR_TYPE_NULL, "TYPE62", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE63", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE64", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE65", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE66", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE67", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE68", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE69", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE70", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE71", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE72", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE73", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE74", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE75", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE76", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE77", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE78", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE79", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE80", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE81", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE82", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE83", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE84", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE85", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE86", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE87", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE88", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE89", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE90", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE91", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE92", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE93", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE94", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE95", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE96", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE97", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE98", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 99 */ {LDNS_RR_TYPE_SPF, "SPF", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 }, /* UINFO [IANA-Reserved] */ {LDNS_RR_TYPE_NULL, "TYPE100", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* UID [IANA-Reserved] */ {LDNS_RR_TYPE_NULL, "TYPE101", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* GID [IANA-Reserved] */ {LDNS_RR_TYPE_NULL, "TYPE102", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* UNSPEC [IANA-Reserved] */ {LDNS_RR_TYPE_NULL, "TYPE103", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 104 */ {LDNS_RR_TYPE_NID, "NID", 2, 2, type_nid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 105 */ {LDNS_RR_TYPE_L32, "L32", 2, 2, type_l32_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 106 */ {LDNS_RR_TYPE_L64, "L64", 2, 2, type_l64_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 107 */ {LDNS_RR_TYPE_LP, "LP", 2, 2, type_lp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 108 */ {LDNS_RR_TYPE_EUI48, "EUI48", 1, 1, type_eui48_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 109 */ {LDNS_RR_TYPE_EUI64, "EUI64", 1, 1, type_eui64_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE110", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE111", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE112", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE113", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE114", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE115", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE116", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE117", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE118", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE119", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE120", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE121", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE122", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE123", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE124", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE125", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE126", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE127", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE128", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE129", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE130", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE131", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE132", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE133", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE134", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE135", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE136", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE137", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE138", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE139", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE140", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE141", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE142", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE143", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE144", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE145", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE146", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE147", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE148", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE149", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE150", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE151", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE152", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE153", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE154", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE155", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE156", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE157", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE158", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE159", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE160", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE161", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE162", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE163", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE164", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE165", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE166", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE167", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE168", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE169", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE170", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE171", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE172", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE173", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE174", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE175", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE176", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE177", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE178", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE179", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE180", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE181", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE182", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE183", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE184", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE185", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE186", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE187", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE188", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE189", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE190", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE191", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE192", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE193", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE194", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE195", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE196", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE197", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE198", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE199", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE200", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE201", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE202", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE203", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE204", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE205", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE206", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE207", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE208", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE209", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE210", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE211", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE212", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE213", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE214", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE215", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE216", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE217", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE218", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE219", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE220", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE221", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE222", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE223", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE224", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE225", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE226", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE227", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE228", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE229", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE230", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE231", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE232", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE233", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE234", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE235", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE236", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE237", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE238", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE239", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE240", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE241", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE242", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE243", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE244", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE245", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE246", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE247", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE248", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* LDNS_RDF_TYPE_INT16_DATA takes two fields (length and data) as one. * So, unlike RFC 2930 spec, we have 7 min/max rdf's i.s.o. 8/9. */ /* 249 */ {LDNS_RR_TYPE_TKEY, "TKEY", 7, 7, type_tkey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* LDNS_RDF_TYPE_INT16_DATA takes two fields (length and data) as one. * So, unlike RFC 2930 spec, we have 7 min/max rdf's i.s.o. 8/9. */ /* 250 */ {LDNS_RR_TYPE_TSIG, "TSIG", 7, 7, type_tsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* IXFR: A request for a transfer of an incremental zone transfer */ {LDNS_RR_TYPE_NULL, "TYPE251", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* AXFR: A request for a transfer of an entire zone */ {LDNS_RR_TYPE_NULL, "TYPE252", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* MAILB: A request for mailbox-related records (MB, MG or MR) */ {LDNS_RR_TYPE_NULL, "TYPE253", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* MAILA: A request for mail agent RRs (Obsolete - see MX) */ {LDNS_RR_TYPE_NULL, "TYPE254", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* ANY: A request for all (available) records */ {LDNS_RR_TYPE_NULL, "TYPE255", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #ifdef RRTYPE_URI /* 256 */ {LDNS_RR_TYPE_URI, "URI", 3, 3, type_uri_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #else {LDNS_RR_TYPE_NULL, "TYPE256", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #endif /* 257 */ {LDNS_RR_TYPE_CAA, "CAA", 3, 3, type_caa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* split in array, no longer contiguous */ #ifdef RRTYPE_TA /* 32768 */ {LDNS_RR_TYPE_TA, "TA", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #else {LDNS_RR_TYPE_NULL, "TYPE32768", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, #endif /* 32769 */ {LDNS_RR_TYPE_DLV, "DLV", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 } }; /** \endcond */ /** * \def LDNS_RDATA_FIELD_DESCRIPTORS_COUNT * computes the number of rdata fields */ #define LDNS_RDATA_FIELD_DESCRIPTORS_COUNT \ (sizeof(rdata_field_descriptors)/sizeof(rdata_field_descriptors[0])) /*---------------------------------------------------------------------------* * The functions below return an bitmap RDF with the space required to set * or unset all known RR types. Arguably these functions are better situated * in rdata.c, however for the space calculation it is necesarry to walk * through rdata_field_descriptors which is not easily possible from anywhere * other than rr.c where it is declared static. * * Alternatively rr.c could have provided an iterator for rr_type or * rdf_descriptors, but this seemed overkill for internal use only. */ static ldns_rr_descriptor* rdata_field_descriptors_end = &rdata_field_descriptors[LDNS_RDATA_FIELD_DESCRIPTORS_COUNT]; /* From RFC3845: * * 2.1.2. The List of Type Bit Map(s) Field * * The RR type space is split into 256 window blocks, each representing * the low-order 8 bits of the 16-bit RR type space. Each block that * has at least one active RR type is encoded using a single octet * window number (from 0 to 255), a single octet bitmap length (from 1 * to 32) indicating the number of octets used for the window block's * bitmap, and up to 32 octets (256 bits) of bitmap. * * Window blocks are present in the NSEC RR RDATA in increasing * numerical order. * * "|" denotes concatenation * * Type Bit Map(s) Field = ( Window Block # | Bitmap Length | Bitmap ) + * * * * Blocks with no types present MUST NOT be included. Trailing zero * octets in the bitmap MUST be omitted. The length of each block's * bitmap is determined by the type code with the largest numerical * value within that block, among the set of RR types present at the * NSEC RR's owner name. Trailing zero octets not specified MUST be * interpreted as zero octets. */ static ldns_status ldns_rdf_bitmap_known_rr_types_set(ldns_rdf** rdf, int value) { uint8_t window; /* most significant octet of type */ uint8_t subtype; /* least significant octet of type */ uint16_t windows[256] /* Max subtype per window */ #ifndef S_SPLINT_S = { 0 } #endif ; ldns_rr_descriptor* d; /* used to traverse rdata_field_descriptors */ size_t i; /* used to traverse windows array */ size_t sz; /* size needed for type bitmap rdf */ uint8_t* data = NULL; /* rdf data */ uint8_t* dptr; /* used to itraverse rdf data */ assert(rdf != NULL); /* Which windows need to be in the bitmap rdf? */ for (d=rdata_field_descriptors; d < rdata_field_descriptors_end; d++) { window = d->_type >> 8; subtype = d->_type & 0xff; if (windows[window] < subtype) { windows[window] = subtype; } } /* How much space do we need in the rdf for those windows? */ sz = 0; for (i = 0; i < 256; i++) { if (windows[i]) { sz += windows[i] / 8 + 3; } } if (sz > 0) { /* Format rdf data according RFC3845 Section 2.1.2 (see above) */ dptr = data = LDNS_XMALLOC(uint8_t, sz); memset(data, value, sz); if (!data) { return LDNS_STATUS_MEM_ERR; } for (i = 0; i < 256; i++) { if (windows[i]) { *dptr++ = (uint8_t)i; *dptr++ = (uint8_t)(windows[i] / 8 + 1); dptr += dptr[-1]; } } } /* Allocate and return rdf structure for the data */ *rdf = ldns_rdf_new(LDNS_RDF_TYPE_BITMAP, sz, data); if (!*rdf) { LDNS_FREE(data); return LDNS_STATUS_MEM_ERR; } return LDNS_STATUS_OK; } ldns_status ldns_rdf_bitmap_known_rr_types_space(ldns_rdf** rdf) { return ldns_rdf_bitmap_known_rr_types_set(rdf, 0); } ldns_status ldns_rdf_bitmap_known_rr_types(ldns_rdf** rdf) { return ldns_rdf_bitmap_known_rr_types_set(rdf, 255); } /* End of RDF bitmap functions *---------------------------------------------------------------------------*/ const ldns_rr_descriptor * ldns_rr_descript(uint16_t type) { size_t i; if (type < LDNS_RDATA_FIELD_DESCRIPTORS_COMMON) { return &rdata_field_descriptors[type]; } else { /* because not all array index equals type code */ for (i = LDNS_RDATA_FIELD_DESCRIPTORS_COMMON; i < LDNS_RDATA_FIELD_DESCRIPTORS_COUNT; i++) { if (rdata_field_descriptors[i]._type == type) { return &rdata_field_descriptors[i]; } } return &rdata_field_descriptors[0]; } } size_t ldns_rr_descriptor_minimum(const ldns_rr_descriptor *descriptor) { if (descriptor) { return descriptor->_minimum; } else { return 0; } } size_t ldns_rr_descriptor_maximum(const ldns_rr_descriptor *descriptor) { if (descriptor) { if (descriptor->_variable != LDNS_RDF_TYPE_NONE) { /* Should really be SIZE_MAX... bad FreeBSD. */ return UINT_MAX; } else { return descriptor->_maximum; } } else { return 0; } } ldns_rdf_type ldns_rr_descriptor_field_type(const ldns_rr_descriptor *descriptor, size_t index) { assert(descriptor != NULL); assert(index < descriptor->_maximum || descriptor->_variable != LDNS_RDF_TYPE_NONE); if (index < descriptor->_maximum) { return descriptor->_wireformat[index]; } else { return descriptor->_variable; } } ldns_rr_type ldns_get_rr_type_by_name(const char *name) { unsigned int i; const char *desc_name; const ldns_rr_descriptor *desc; /* TYPEXX representation */ if (strlen(name) > 4 && strncasecmp(name, "TYPE", 4) == 0) { return atoi(name + 4); } /* Normal types */ for (i = 0; i < (unsigned int) LDNS_RDATA_FIELD_DESCRIPTORS_COUNT; i++) { desc = &rdata_field_descriptors[i]; desc_name = desc->_name; if(desc_name && strlen(name) == strlen(desc_name) && strncasecmp(name, desc_name, strlen(desc_name)) == 0) { /* because not all array index equals type code */ return desc->_type; } } /* special cases for query types */ if (strlen(name) == 4 && strncasecmp(name, "IXFR", 4) == 0) { return 251; } else if (strlen(name) == 4 && strncasecmp(name, "AXFR", 4) == 0) { return 252; } else if (strlen(name) == 5 && strncasecmp(name, "MAILB", 5) == 0) { return 253; } else if (strlen(name) == 5 && strncasecmp(name, "MAILA", 5) == 0) { return 254; } else if (strlen(name) == 3 && strncasecmp(name, "ANY", 3) == 0) { return 255; } return 0; } ldns_rr_class ldns_get_rr_class_by_name(const char *name) { ldns_lookup_table *lt; /* CLASSXX representation */ if (strlen(name) > 5 && strncasecmp(name, "CLASS", 5) == 0) { return atoi(name + 5); } /* Normal types */ lt = ldns_lookup_by_name(ldns_rr_classes, name); if (lt) { return lt->id; } return 0; } ldns_rr_type ldns_rdf2rr_type(const ldns_rdf *rd) { ldns_rr_type r; if (!rd) { return 0; } if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_TYPE) { return 0; } r = (ldns_rr_type) ldns_rdf2native_int16(rd); return r; } ldns_rr_type ldns_rr_list_type(const ldns_rr_list *rr_list) { if (rr_list && ldns_rr_list_rr_count(rr_list) > 0) { return ldns_rr_get_type(ldns_rr_list_rr(rr_list, 0)); } else { return 0; } } ldns_rdf * ldns_rr_list_owner(const ldns_rr_list *rr_list) { if (rr_list && ldns_rr_list_rr_count(rr_list) > 0) { return ldns_rr_owner(ldns_rr_list_rr(rr_list, 0)); } else { return NULL; } } Net-LDNS-0.75/src/ldns/rr_functions.c000644 000770 000024 00000020740 12471046240 017725 0ustar00calledstaff000000 000000 /* * rr_function.c * * function that operate on specific rr types * * (c) NLnet Labs, 2004-2006 * See the file LICENSE for the license */ /* * These come strait from perldoc Net::DNS::RR::xxx * first the read variant, then the write. This is * not complete. */ #include #include #include #include /** * return a specific rdf * \param[in] type type of RR * \param[in] rr the rr itself * \param[in] pos at which postion to get it * \return the rdf sought */ static ldns_rdf * ldns_rr_function(ldns_rr_type type, const ldns_rr *rr, size_t pos) { if (!rr || ldns_rr_get_type(rr) != type) { return NULL; } return ldns_rr_rdf(rr, pos); } /** * set a specific rdf * \param[in] type type of RR * \param[in] rr the rr itself * \param[in] rdf the rdf to set * \param[in] pos at which postion to set it * \return true or false */ static bool ldns_rr_set_function(ldns_rr_type type, ldns_rr *rr, ldns_rdf *rdf, size_t pos) { ldns_rdf *pop; if (!rr || ldns_rr_get_type(rr) != type) { return false; } pop = ldns_rr_set_rdf(rr, rdf, pos); ldns_rdf_deep_free(pop); return true; } /* A/AAAA records */ ldns_rdf * ldns_rr_a_address(const ldns_rr *r) { /* 2 types to check, cannot use the macro */ if (!r || (ldns_rr_get_type(r) != LDNS_RR_TYPE_A && ldns_rr_get_type(r) != LDNS_RR_TYPE_AAAA)) { return NULL; } return ldns_rr_rdf(r, 0); } bool ldns_rr_a_set_address(ldns_rr *r, ldns_rdf *f) { /* 2 types to check, cannot use the macro... */ ldns_rdf *pop; if (!r || (ldns_rr_get_type(r) != LDNS_RR_TYPE_A && ldns_rr_get_type(r) != LDNS_RR_TYPE_AAAA)) { return false; } pop = ldns_rr_set_rdf(r, f, 0); if (pop) { LDNS_FREE(pop); return true; } else { return false; } } /* NS record */ ldns_rdf * ldns_rr_ns_nsdname(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_NS, r, 0); } /* MX record */ ldns_rdf * ldns_rr_mx_preference(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_MX, r, 0); } ldns_rdf * ldns_rr_mx_exchange(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_MX, r, 1); } /* RRSIG record */ ldns_rdf * ldns_rr_rrsig_typecovered(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 0); } bool ldns_rr_rrsig_set_typecovered(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 0); } ldns_rdf * ldns_rr_rrsig_algorithm(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 1); } bool ldns_rr_rrsig_set_algorithm(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 1); } ldns_rdf * ldns_rr_rrsig_labels(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 2); } bool ldns_rr_rrsig_set_labels(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 2); } ldns_rdf * ldns_rr_rrsig_origttl(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 3); } bool ldns_rr_rrsig_set_origttl(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 3); } ldns_rdf * ldns_rr_rrsig_expiration(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 4); } bool ldns_rr_rrsig_set_expiration(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 4); } ldns_rdf * ldns_rr_rrsig_inception(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 5); } bool ldns_rr_rrsig_set_inception(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 5); } ldns_rdf * ldns_rr_rrsig_keytag(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 6); } bool ldns_rr_rrsig_set_keytag(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 6); } ldns_rdf * ldns_rr_rrsig_signame(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 7); } bool ldns_rr_rrsig_set_signame(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 7); } ldns_rdf * ldns_rr_rrsig_sig(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 8); } bool ldns_rr_rrsig_set_sig(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 8); } /* DNSKEY record */ ldns_rdf * ldns_rr_dnskey_flags(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 0); } bool ldns_rr_dnskey_set_flags(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 0); } ldns_rdf * ldns_rr_dnskey_protocol(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 1); } bool ldns_rr_dnskey_set_protocol(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 1); } ldns_rdf * ldns_rr_dnskey_algorithm(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 2); } bool ldns_rr_dnskey_set_algorithm(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 2); } ldns_rdf * ldns_rr_dnskey_key(const ldns_rr *r) { return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 3); } bool ldns_rr_dnskey_set_key(ldns_rr *r, ldns_rdf *f) { return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 3); } size_t ldns_rr_dnskey_key_size_raw(const unsigned char* keydata, const size_t len, const ldns_algorithm alg) { /* for DSA keys */ uint8_t t; /* for RSA keys */ uint16_t exp; uint16_t int16; switch ((ldns_signing_algorithm)alg) { case LDNS_SIGN_DSA: case LDNS_SIGN_DSA_NSEC3: if (len > 0) { t = keydata[0]; return (64 + t*8)*8; } else { return 0; } break; case LDNS_SIGN_RSAMD5: case LDNS_SIGN_RSASHA1: case LDNS_SIGN_RSASHA1_NSEC3: #ifdef USE_SHA2 case LDNS_SIGN_RSASHA256: case LDNS_SIGN_RSASHA512: #endif if (len > 0) { if (keydata[0] == 0) { /* big exponent */ if (len > 3) { memmove(&int16, keydata + 1, 2); exp = ntohs(int16); return (len - exp - 3)*8; } else { return 0; } } else { exp = keydata[0]; return (len-exp-1)*8; } } else { return 0; } break; #ifdef USE_GOST case LDNS_SIGN_ECC_GOST: return 512; #endif #ifdef USE_ECDSA case LDNS_SIGN_ECDSAP256SHA256: return 256; case LDNS_SIGN_ECDSAP384SHA384: return 384; #endif case LDNS_SIGN_HMACMD5: return len; default: return 0; } } size_t ldns_rr_dnskey_key_size(const ldns_rr *key) { if (!key || !ldns_rr_dnskey_key(key) || !ldns_rr_dnskey_algorithm(key)) { return 0; } return ldns_rr_dnskey_key_size_raw((unsigned char*)ldns_rdf_data(ldns_rr_dnskey_key(key)), ldns_rdf_size(ldns_rr_dnskey_key(key)), ldns_rdf2native_int8(ldns_rr_dnskey_algorithm(key)) ); } uint32_t ldns_soa_serial_identity(uint32_t ATTR_UNUSED(unused), void *data) { return (uint32_t) (intptr_t) data; } uint32_t ldns_soa_serial_increment(uint32_t s, void *ATTR_UNUSED(unused)) { return ldns_soa_serial_increment_by(s, (void *)1); } uint32_t ldns_soa_serial_increment_by(uint32_t s, void *data) { return s + (intptr_t) data; } uint32_t ldns_soa_serial_datecounter(uint32_t s, void *data) { struct tm tm; char s_str[11]; int32_t new_s; time_t t = data ? (time_t) (intptr_t) data : ldns_time(NULL); (void) strftime(s_str, 11, "%Y%m%d00", localtime_r(&t, &tm)); new_s = (int32_t) atoi(s_str); return new_s - ((int32_t) s) <= 0 ? s+1 : ((uint32_t) new_s); } uint32_t ldns_soa_serial_unixtime(uint32_t s, void *data) { int32_t new_s = data ? (int32_t) (intptr_t) data : (int32_t) ldns_time(NULL); return new_s - ((int32_t) s) <= 0 ? s+1 : ((uint32_t) new_s); } void ldns_rr_soa_increment(ldns_rr *soa) { ldns_rr_soa_increment_func_data(soa, ldns_soa_serial_increment, NULL); } void ldns_rr_soa_increment_func(ldns_rr *soa, ldns_soa_serial_increment_func_t f) { ldns_rr_soa_increment_func_data(soa, f, NULL); } void ldns_rr_soa_increment_func_data(ldns_rr *soa, ldns_soa_serial_increment_func_t f, void *data) { ldns_rdf *prev_soa_serial_rdf; if ( !soa || !f || ldns_rr_get_type(soa) != LDNS_RR_TYPE_SOA || !ldns_rr_rdf(soa, 2)) { return; } prev_soa_serial_rdf = ldns_rr_set_rdf( soa , ldns_native2rdf_int32( LDNS_RDF_TYPE_INT32 , (*f)( ldns_rdf2native_int32( ldns_rr_rdf(soa, 2)) , data ) ) , 2 ); LDNS_FREE(prev_soa_serial_rdf); } void ldns_rr_soa_increment_func_int(ldns_rr *soa, ldns_soa_serial_increment_func_t f, int data) { ldns_rr_soa_increment_func_data(soa, f, (void *) (intptr_t) data); } Net-LDNS-0.75/src/ldns/sha1.c000644 000770 000024 00000014123 12471046240 016044 0ustar00calledstaff000000 000000 /* * modified for ldns by Jelte Jansen, original taken from OpenBSD: * * SHA-1 in C * By Steve Reid * 100% Public Domain * * Test Vectors (from FIPS PUB 180-1) * "abc" * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 * A million repetitions of "a" * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ /* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ #include #include #include #define SHA1HANDSOFF 1 /* Copies data before messing with it. */ #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ /* I got the idea of expanding during the round function from SSLeay */ #if BYTE_ORDER == LITTLE_ENDIAN #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ |(rol(block->l[i],8)&0x00FF00FF)) #else #define blk0(i) block->l[i] #endif #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ ^block->l[(i+2)&15]^block->l[i&15],1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); /* Hash a single 512-bit block. This is the core of the algorithm. */ void ldns_sha1_transform(uint32_t state[5], const unsigned char buffer[LDNS_SHA1_BLOCK_LENGTH]) { uint32_t a, b, c, d, e; typedef union { unsigned char c[64]; unsigned int l[16]; } CHAR64LONG16; CHAR64LONG16* block; #ifdef SHA1HANDSOFF unsigned char workspace[LDNS_SHA1_BLOCK_LENGTH]; block = (CHAR64LONG16 *)workspace; memmove(block, buffer, LDNS_SHA1_BLOCK_LENGTH); #else block = (CHAR64LONG16 *)buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } /* SHA1Init - Initialize new context */ void ldns_sha1_init(ldns_sha1_ctx *context) { /* SHA1 initialization constants */ context->count = 0; context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; } /* Run your data through this. */ void ldns_sha1_update(ldns_sha1_ctx *context, const unsigned char *data, unsigned int len) { unsigned int i; unsigned int j; j = (unsigned)(uint32_t)((context->count >> 3) & 63); context->count += (len << 3); if ((j + len) > 63) { memmove(&context->buffer[j], data, (i = 64 - j)); ldns_sha1_transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { ldns_sha1_transform(context->state, &data[i]); } j = 0; } else i = 0; memmove(&context->buffer[j], &data[i], len - i); } /* Add padding and return the message digest. */ void ldns_sha1_final(unsigned char digest[LDNS_SHA1_DIGEST_LENGTH], ldns_sha1_ctx *context) { unsigned int i; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count >> ((7 - (i & 7)) * 8)) & 255); /* Endian independent */ } ldns_sha1_update(context, (unsigned char *)"\200", 1); while ((context->count & 504) != 448) { ldns_sha1_update(context, (unsigned char *)"\0", 1); } ldns_sha1_update(context, finalcount, 8); /* Should cause a SHA1Transform() */ if (digest != NULL) for (i = 0; i < LDNS_SHA1_DIGEST_LENGTH; i++) { digest[i] = (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); } #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ ldns_sha1_transform(context->state, context->buffer); #endif } unsigned char * ldns_sha1(unsigned char *data, unsigned int data_len, unsigned char *digest) { ldns_sha1_ctx ctx; ldns_sha1_init(&ctx); ldns_sha1_update(&ctx, data, data_len); ldns_sha1_final(digest, &ctx); return digest; } Net-LDNS-0.75/src/ldns/sha2.c000644 000770 000024 00000073564 12471046240 016063 0ustar00calledstaff000000 000000 /* * FILE: sha2.c * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ * * Copyright (c) 2000-2001, Aaron D. Gifford * All rights reserved. * * Modified by Jelte Jansen to fit in ldns, and not clash with any * system-defined SHA code. * Changes: * - Renamed (external) functions and constants to fit ldns style * - Removed _End and _Data functions * - Added ldns_shaX(data, len, digest) convenience functions * - Removed prototypes of _Transform functions and made those static * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ */ #include #include /* memcpy()/memset() or bcopy()/bzero() */ #include /* assert() */ #include /* * ASSERT NOTE: * Some sanity checking code is included using assert(). On my FreeBSD * system, this additional code can be removed by compiling with NDEBUG * defined. Check your own systems manpage on assert() to see how to * compile WITHOUT the sanity checking code on your system. * * UNROLLED TRANSFORM LOOP NOTE: * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform * loop version for the hash transform rounds (defined using macros * later in this file). Either define on the command line, for example: * * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c * * or define below: * * #define SHA2_UNROLL_TRANSFORM * */ /*** SHA-256/384/512 Machine Architecture Definitions *****************/ /* * BYTE_ORDER NOTE: * * Please make sure that your system defines BYTE_ORDER. If your * architecture is little-endian, make sure it also defines * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are * equivilent. * * If your system does not define the above, then you can do so by * hand like this: * * #define LITTLE_ENDIAN 1234 * #define BIG_ENDIAN 4321 * * And for little-endian machines, add: * * #define BYTE_ORDER LITTLE_ENDIAN * * Or for big-endian machines: * * #define BYTE_ORDER BIG_ENDIAN * * The FreeBSD machine this was written on defines BYTE_ORDER * appropriately by including (which in turn includes * where the appropriate definitions are actually * made). */ #if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) #error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN #endif typedef uint8_t sha2_byte; /* Exactly 1 byte */ typedef uint32_t sha2_word32; /* Exactly 4 bytes */ #ifdef S_SPLINT_S typedef unsigned long long sha2_word64; /* lint 8 bytes */ #else typedef uint64_t sha2_word64; /* Exactly 8 bytes */ #endif /*** SHA-256/384/512 Various Length Definitions ***********************/ /* NOTE: Most of these are in sha2.h */ #define ldns_sha256_SHORT_BLOCK_LENGTH (LDNS_SHA256_BLOCK_LENGTH - 8) #define ldns_sha384_SHORT_BLOCK_LENGTH (LDNS_SHA384_BLOCK_LENGTH - 16) #define ldns_sha512_SHORT_BLOCK_LENGTH (LDNS_SHA512_BLOCK_LENGTH - 16) /*** ENDIAN REVERSAL MACROS *******************************************/ #if BYTE_ORDER == LITTLE_ENDIAN #define REVERSE32(w,x) { \ sha2_word32 tmp = (w); \ tmp = (tmp >> 16) | (tmp << 16); \ (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ } #ifndef S_SPLINT_S #define REVERSE64(w,x) { \ sha2_word64 tmp = (w); \ tmp = (tmp >> 32) | (tmp << 32); \ tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ ((tmp & 0x0000ffff0000ffffULL) << 16); \ } #else /* splint */ #define REVERSE64(w,x) /* splint */ #endif /* splint */ #endif /* BYTE_ORDER == LITTLE_ENDIAN */ /* * Macro for incrementally adding the unsigned 64-bit integer n to the * unsigned 128-bit integer (represented using a two-element array of * 64-bit words): */ #define ADDINC128(w,n) { \ (w)[0] += (sha2_word64)(n); \ if ((w)[0] < (n)) { \ (w)[1]++; \ } \ } #ifdef S_SPLINT_S #undef ADDINC128 #define ADDINC128(w,n) /* splint */ #endif /* * Macros for copying blocks of memory and for zeroing out ranges * of memory. Using these macros makes it easy to switch from * using memset()/memcpy() and using bzero()/bcopy(). * * Please define either SHA2_USE_MEMSET_MEMCPY or define * SHA2_USE_BZERO_BCOPY depending on which function set you * choose to use: */ #if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) /* Default to memset()/memcpy() if no option is specified */ #define SHA2_USE_MEMSET_MEMCPY 1 #endif #if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) /* Abort with an error if BOTH options are defined */ #error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! #endif #ifdef SHA2_USE_MEMSET_MEMCPY #define MEMSET_BZERO(p,l) memset((p), 0, (l)) #define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) #endif #ifdef SHA2_USE_BZERO_BCOPY #define MEMSET_BZERO(p,l) bzero((p), (l)) #define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) #endif /*** THE SIX LOGICAL FUNCTIONS ****************************************/ /* * Bit shifting and rotation (used by the six SHA-XYZ logical functions: * * NOTE: The naming of R and S appears backwards here (R is a SHIFT and * S is a ROTATION) because the SHA-256/384/512 description document * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this * same "backwards" definition. */ /* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ #define R(b,x) ((x) >> (b)) /* 32-bit Rotate-right (used in SHA-256): */ #define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) /* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ #define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) /* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ #define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) /* Four of six logical functions used in SHA-256: */ #define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) #define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) #define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) #define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) /* Four of six logical functions used in SHA-384 and SHA-512: */ #define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) #define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) #define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) #define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ /* Hash constant words K for SHA-256: */ static const sha2_word32 K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* initial hash value H for SHA-256: */ static const sha2_word32 ldns_sha256_initial_hash_value[8] = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL }; /* Hash constant words K for SHA-384 and SHA-512: */ static const sha2_word64 K512[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; /* initial hash value H for SHA-384 */ static const sha2_word64 sha384_initial_hash_value[8] = { 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL }; /* initial hash value H for SHA-512 */ static const sha2_word64 sha512_initial_hash_value[8] = { 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL }; /*** SHA-256: *********************************************************/ void ldns_sha256_init(ldns_sha256_CTX* context) { if (context == (ldns_sha256_CTX*)0) { return; } MEMCPY_BCOPY(context->state, ldns_sha256_initial_hash_value, LDNS_SHA256_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, LDNS_SHA256_BLOCK_LENGTH); context->bitcount = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-256 round macros: */ #if BYTE_ORDER == LITTLE_ENDIAN #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ REVERSE32(*data++, W256[j]); \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + W256[j]; \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + (W256[j] = *data++); \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ #endif /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND256(a,b,c,d,e,f,g,h) \ s0 = W256[(j+1)&0x0f]; \ s0 = sigma0_256(s0); \ s1 = W256[(j+14)&0x0f]; \ s1 = sigma1_256(s1); \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ static void ldns_sha256_Transform(ldns_sha256_CTX* context, const sha2_word32* data) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; sha2_word32 T1, *W256; int j; W256 = (sha2_word32*)context->buffer; /* initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { /* Rounds 0 to 15 (unrolled): */ ROUND256_0_TO_15(a,b,c,d,e,f,g,h); ROUND256_0_TO_15(h,a,b,c,d,e,f,g); ROUND256_0_TO_15(g,h,a,b,c,d,e,f); ROUND256_0_TO_15(f,g,h,a,b,c,d,e); ROUND256_0_TO_15(e,f,g,h,a,b,c,d); ROUND256_0_TO_15(d,e,f,g,h,a,b,c); ROUND256_0_TO_15(c,d,e,f,g,h,a,b); ROUND256_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds to 64: */ do { ROUND256(a,b,c,d,e,f,g,h); ROUND256(h,a,b,c,d,e,f,g); ROUND256(g,h,a,b,c,d,e,f); ROUND256(f,g,h,a,b,c,d,e); ROUND256(e,f,g,h,a,b,c,d); ROUND256(d,e,f,g,h,a,b,c); ROUND256(c,d,e,f,g,h,a,b); ROUND256(b,c,d,e,f,g,h,a); } while (j < 64); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ static void ldns_sha256_Transform(ldns_sha256_CTX* context, const sha2_word32* data) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; sha2_word32 T1, T2, *W256; int j; W256 = (sha2_word32*)context->buffer; /* initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { #if BYTE_ORDER == LITTLE_ENDIAN /* Copy data while converting to host byte order */ REVERSE32(*data++,W256[j]); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; #else /* BYTE_ORDER == LITTLE_ENDIAN */ /* Apply the SHA-256 compression function to update a..h with copy */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); #endif /* BYTE_ORDER == LITTLE_ENDIAN */ T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W256[(j+1)&0x0f]; s0 = sigma0_256(s0); s1 = W256[(j+14)&0x0f]; s1 = sigma1_256(s1); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 64); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void ldns_sha256_update(ldns_sha256_CTX* context, const sha2_byte *data, size_t len) { size_t freespace, usedspace; if (len == 0) { /* Calling with no data is valid - we do nothing */ return; } /* Sanity check: */ assert(context != (ldns_sha256_CTX*)0 && data != (sha2_byte*)0); usedspace = (context->bitcount >> 3) % LDNS_SHA256_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = LDNS_SHA256_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); context->bitcount += freespace << 3; len -= freespace; data += freespace; ldns_sha256_Transform(context, (sha2_word32*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); context->bitcount += len << 3; /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= LDNS_SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ ldns_sha256_Transform(context, (sha2_word32*)data); context->bitcount += LDNS_SHA256_BLOCK_LENGTH << 3; len -= LDNS_SHA256_BLOCK_LENGTH; data += LDNS_SHA256_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ MEMCPY_BCOPY(context->buffer, data, len); context->bitcount += len << 3; } /* Clean up: */ usedspace = freespace = 0; } typedef union _ldns_sha2_buffer_union { uint8_t* theChars; uint64_t* theLongs; } ldns_sha2_buffer_union; void ldns_sha256_final(sha2_byte digest[], ldns_sha256_CTX* context) { sha2_word32 *d = (sha2_word32*)digest; size_t usedspace; ldns_sha2_buffer_union cast_var; /* Sanity check: */ assert(context != (ldns_sha256_CTX*)0); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { usedspace = (context->bitcount >> 3) % LDNS_SHA256_BLOCK_LENGTH; #if BYTE_ORDER == LITTLE_ENDIAN /* Convert FROM host byte order */ REVERSE64(context->bitcount,context->bitcount); #endif if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= ldns_sha256_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ MEMSET_BZERO(&context->buffer[usedspace], ldns_sha256_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < LDNS_SHA256_BLOCK_LENGTH) { MEMSET_BZERO(&context->buffer[usedspace], LDNS_SHA256_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ ldns_sha256_Transform(context, (sha2_word32*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, ldns_sha256_SHORT_BLOCK_LENGTH); } } else { /* Set-up for the last transform: */ MEMSET_BZERO(context->buffer, ldns_sha256_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Set the bit count: */ cast_var.theChars = context->buffer; cast_var.theLongs[ldns_sha256_SHORT_BLOCK_LENGTH / 8] = context->bitcount; /* final transform: */ ldns_sha256_Transform(context, (sha2_word32*)context->buffer); #if BYTE_ORDER == LITTLE_ENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { REVERSE32(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else MEMCPY_BCOPY(d, context->state, LDNS_SHA256_DIGEST_LENGTH); #endif } /* Clean up state data: */ MEMSET_BZERO(context, sizeof(ldns_sha256_CTX)); usedspace = 0; } unsigned char * ldns_sha256(unsigned char *data, unsigned int data_len, unsigned char *digest) { ldns_sha256_CTX ctx; ldns_sha256_init(&ctx); ldns_sha256_update(&ctx, data, data_len); ldns_sha256_final(digest, &ctx); return digest; } /*** SHA-512: *********************************************************/ void ldns_sha512_init(ldns_sha512_CTX* context) { if (context == (ldns_sha512_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha512_initial_hash_value, LDNS_SHA512_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, LDNS_SHA512_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ #if BYTE_ORDER == LITTLE_ENDIAN #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ REVERSE64(*data++, W512[j]); \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + W512[j]; \ (d) += T1, \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ j++ #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + (W512[j] = *data++); \ (d) += T1; \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ #endif /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND512(a,b,c,d,e,f,g,h) \ s0 = W512[(j+1)&0x0f]; \ s0 = sigma0_512(s0); \ s1 = W512[(j+14)&0x0f]; \ s1 = sigma1_512(s1); \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ static void ldns_sha512_Transform(ldns_sha512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; int j; /* initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { ROUND512_0_TO_15(a,b,c,d,e,f,g,h); ROUND512_0_TO_15(h,a,b,c,d,e,f,g); ROUND512_0_TO_15(g,h,a,b,c,d,e,f); ROUND512_0_TO_15(f,g,h,a,b,c,d,e); ROUND512_0_TO_15(e,f,g,h,a,b,c,d); ROUND512_0_TO_15(d,e,f,g,h,a,b,c); ROUND512_0_TO_15(c,d,e,f,g,h,a,b); ROUND512_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds up to 79: */ do { ROUND512(a,b,c,d,e,f,g,h); ROUND512(h,a,b,c,d,e,f,g); ROUND512(g,h,a,b,c,d,e,f); ROUND512(f,g,h,a,b,c,d,e); ROUND512(e,f,g,h,a,b,c,d); ROUND512(d,e,f,g,h,a,b,c); ROUND512(c,d,e,f,g,h,a,b); ROUND512(b,c,d,e,f,g,h,a); } while (j < 80); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ static void ldns_sha512_Transform(ldns_sha512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; int j; /* initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ REVERSE64(*data++, W512[j]); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; #else /* BYTE_ORDER == LITTLE_ENDIAN */ /* Apply the SHA-512 compression function to update a..h with copy */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); #endif /* BYTE_ORDER == LITTLE_ENDIAN */ T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W512[(j+1)&0x0f]; s0 = sigma0_512(s0); s1 = W512[(j+14)&0x0f]; s1 = sigma1_512(s1); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 80); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void ldns_sha512_update(ldns_sha512_CTX* context, const sha2_byte *data, size_t len) { size_t freespace, usedspace; if (len == 0) { /* Calling with no data is valid - we do nothing */ return; } /* Sanity check: */ assert(context != (ldns_sha512_CTX*)0 && data != (sha2_byte*)0); usedspace = (context->bitcount[0] >> 3) % LDNS_SHA512_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = LDNS_SHA512_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; ldns_sha512_Transform(context, (sha2_word64*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); ADDINC128(context->bitcount, len << 3); /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= LDNS_SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ ldns_sha512_Transform(context, (sha2_word64*)data); ADDINC128(context->bitcount, LDNS_SHA512_BLOCK_LENGTH << 3); len -= LDNS_SHA512_BLOCK_LENGTH; data += LDNS_SHA512_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ MEMCPY_BCOPY(context->buffer, data, len); ADDINC128(context->bitcount, len << 3); } /* Clean up: */ usedspace = freespace = 0; } static void ldns_sha512_Last(ldns_sha512_CTX* context) { size_t usedspace; ldns_sha2_buffer_union cast_var; usedspace = (context->bitcount[0] >> 3) % LDNS_SHA512_BLOCK_LENGTH; #if BYTE_ORDER == LITTLE_ENDIAN /* Convert FROM host byte order */ REVERSE64(context->bitcount[0],context->bitcount[0]); REVERSE64(context->bitcount[1],context->bitcount[1]); #endif if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= ldns_sha512_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ MEMSET_BZERO(&context->buffer[usedspace], ldns_sha512_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < LDNS_SHA512_BLOCK_LENGTH) { MEMSET_BZERO(&context->buffer[usedspace], LDNS_SHA512_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ ldns_sha512_Transform(context, (sha2_word64*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, LDNS_SHA512_BLOCK_LENGTH - 2); } } else { /* Prepare for final transform: */ MEMSET_BZERO(context->buffer, ldns_sha512_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Store the length of input data (in bits): */ cast_var.theChars = context->buffer; cast_var.theLongs[ldns_sha512_SHORT_BLOCK_LENGTH / 8] = context->bitcount[1]; cast_var.theLongs[ldns_sha512_SHORT_BLOCK_LENGTH / 8 + 1] = context->bitcount[0]; /* final transform: */ ldns_sha512_Transform(context, (sha2_word64*)context->buffer); } void ldns_sha512_final(sha2_byte digest[], ldns_sha512_CTX* context) { sha2_word64 *d = (sha2_word64*)digest; /* Sanity check: */ assert(context != (ldns_sha512_CTX*)0); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { ldns_sha512_Last(context); /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { REVERSE64(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else MEMCPY_BCOPY(d, context->state, LDNS_SHA512_DIGEST_LENGTH); #endif } /* Zero out state data */ MEMSET_BZERO(context, sizeof(ldns_sha512_CTX)); } unsigned char * ldns_sha512(unsigned char *data, unsigned int data_len, unsigned char *digest) { ldns_sha512_CTX ctx; ldns_sha512_init(&ctx); ldns_sha512_update(&ctx, data, data_len); ldns_sha512_final(digest, &ctx); return digest; } /*** SHA-384: *********************************************************/ void ldns_sha384_init(ldns_sha384_CTX* context) { if (context == (ldns_sha384_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha384_initial_hash_value, LDNS_SHA512_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, LDNS_SHA384_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } void ldns_sha384_update(ldns_sha384_CTX* context, const sha2_byte* data, size_t len) { ldns_sha512_update((ldns_sha512_CTX*)context, data, len); } void ldns_sha384_final(sha2_byte digest[], ldns_sha384_CTX* context) { sha2_word64 *d = (sha2_word64*)digest; /* Sanity check: */ assert(context != (ldns_sha384_CTX*)0); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { ldns_sha512_Last((ldns_sha512_CTX*)context); /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 6; j++) { REVERSE64(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else MEMCPY_BCOPY(d, context->state, LDNS_SHA384_DIGEST_LENGTH); #endif } /* Zero out state data */ MEMSET_BZERO(context, sizeof(ldns_sha384_CTX)); } unsigned char * ldns_sha384(unsigned char *data, unsigned int data_len, unsigned char *digest) { ldns_sha384_CTX ctx; ldns_sha384_init(&ctx); ldns_sha384_update(&ctx, data, data_len); ldns_sha384_final(digest, &ctx); return digest; } Net-LDNS-0.75/src/ldns/str2host.c000644 000770 000024 00000112702 12471046240 017002 0ustar00calledstaff000000 000000 /* * str2host.c * * conversion routines from the presentation format * to the host format * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #include #include #ifdef HAVE_NETDB_H #include #endif #include #ifdef HAVE_SYS_PARAM_H #include #endif ldns_status ldns_str2rdf_int16(ldns_rdf **rd, const char *shortstr) { char *end = NULL; uint16_t *r; r = LDNS_MALLOC(uint16_t); if(!r) return LDNS_STATUS_MEM_ERR; *r = htons((uint16_t)strtol((char *)shortstr, &end, 10)); if(*end != 0) { LDNS_FREE(r); return LDNS_STATUS_INVALID_INT; } else { *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_INT16, sizeof(uint16_t), r); LDNS_FREE(r); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } } ldns_status ldns_str2rdf_time(ldns_rdf **rd, const char *time) { /* convert a time YYYYDDMMHHMMSS to wireformat */ uint16_t *r = NULL; struct tm tm; uint32_t l; char *end; /* Try to scan the time... */ r = (uint16_t*)LDNS_MALLOC(uint32_t); if(!r) return LDNS_STATUS_MEM_ERR; memset(&tm, 0, sizeof(tm)); if (strlen(time) == 14 && sscanf(time, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6 ) { tm.tm_year -= 1900; tm.tm_mon--; /* Check values */ if (tm.tm_year < 70) { goto bad_format; } if (tm.tm_mon < 0 || tm.tm_mon > 11) { goto bad_format; } if (tm.tm_mday < 1 || tm.tm_mday > 31) { goto bad_format; } if (tm.tm_hour < 0 || tm.tm_hour > 23) { goto bad_format; } if (tm.tm_min < 0 || tm.tm_min > 59) { goto bad_format; } if (tm.tm_sec < 0 || tm.tm_sec > 59) { goto bad_format; } l = htonl(ldns_mktime_from_utc(&tm)); memcpy(r, &l, sizeof(uint32_t)); *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_TIME, sizeof(uint32_t), r); LDNS_FREE(r); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } else { /* handle it as 32 bits timestamp */ l = htonl((uint32_t)strtol((char*)time, &end, 10)); if(*end != 0) { LDNS_FREE(r); return LDNS_STATUS_ERR; } else { memcpy(r, &l, sizeof(uint32_t)); *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_INT32, sizeof(uint32_t), r); LDNS_FREE(r); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } } bad_format: LDNS_FREE(r); return LDNS_STATUS_INVALID_TIME; } ldns_status ldns_str2rdf_nsec3_salt(ldns_rdf **rd, const char *salt_str) { uint8_t salt_length; int c; int salt_length_str; uint8_t *salt; uint8_t *data; if(rd == NULL) { return LDNS_STATUS_NULL; } salt_length_str = (int)strlen(salt_str); if (salt_length_str == 1 && salt_str[0] == '-') { salt_length_str = 0; } else if (salt_length_str % 2 != 0) { return LDNS_STATUS_INVALID_HEX; } if (salt_length_str > 512) { return LDNS_STATUS_INVALID_HEX; } salt = LDNS_XMALLOC(uint8_t, salt_length_str / 2); if(!salt) { return LDNS_STATUS_MEM_ERR; } for (c = 0; c < salt_length_str; c += 2) { if (isxdigit((int) salt_str[c]) && isxdigit((int) salt_str[c+1])) { salt[c/2] = (uint8_t) ldns_hexdigit_to_int(salt_str[c]) * 16 + ldns_hexdigit_to_int(salt_str[c+1]); } else { LDNS_FREE(salt); return LDNS_STATUS_INVALID_HEX; } } salt_length = (uint8_t) (salt_length_str / 2); data = LDNS_XMALLOC(uint8_t, 1 + salt_length); if(!data) { LDNS_FREE(salt); return LDNS_STATUS_MEM_ERR; } data[0] = salt_length; memcpy(&data[1], salt, salt_length); *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC3_SALT, 1 + salt_length, data); LDNS_FREE(data); LDNS_FREE(salt); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_period(ldns_rdf **rd,const char *period) { uint32_t p; const char *end; /* Allocate required space... */ p = ldns_str2period(period, &end); if (*end != 0) { return LDNS_STATUS_ERR; } else { p = (uint32_t) htonl(p); *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_PERIOD, sizeof(uint32_t), &p); } return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_int32(ldns_rdf **rd, const char *longstr) { char *end; uint16_t *r = NULL; uint32_t l; r = (uint16_t*)LDNS_MALLOC(uint32_t); if(!r) return LDNS_STATUS_MEM_ERR; errno = 0; /* must set to zero before call, note race condition on errno */ if(*longstr == '-') l = htonl((uint32_t)strtol((char*)longstr, &end, 10)); else l = htonl((uint32_t)strtoul((char*)longstr, &end, 10)); if(*end != 0) { LDNS_FREE(r); return LDNS_STATUS_ERR; } else { if (errno == ERANGE) { LDNS_FREE(r); return LDNS_STATUS_SYNTAX_INTEGER_OVERFLOW; } memcpy(r, &l, sizeof(uint32_t)); *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_INT32, sizeof(uint32_t), r); LDNS_FREE(r); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } } ldns_status ldns_str2rdf_int8(ldns_rdf **rd, const char *bytestr) { char *end; uint8_t *r = NULL; r = LDNS_MALLOC(uint8_t); if(!r) return LDNS_STATUS_MEM_ERR; *r = (uint8_t)strtol((char*)bytestr, &end, 10); if(*end != 0) { LDNS_FREE(r); return LDNS_STATUS_ERR; } else { *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_INT8, sizeof(uint8_t), r); LDNS_FREE(r); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } } /* * Checks whether the escaped value at **s is an decimal value or * a 'normally' escaped character (and not eos) * * The string pointer at *s is increased by either 0 (on error), 1 (on * normal escapes), or 3 (on decimals) * * Returns the number of bytes read from the escaped string, or * 0 on error */ INLINE bool parse_escape(uint8_t *ch_p, const char** str_p) { uint16_t val; if ((*str_p)[0] && isdigit((*str_p)[0]) && (*str_p)[1] && isdigit((*str_p)[1]) && (*str_p)[2] && isdigit((*str_p)[2])) { val = (uint16_t)(((*str_p)[0] - '0') * 100 + ((*str_p)[1] - '0') * 10 + ((*str_p)[2] - '0')); if (val > 255) { goto error; } *ch_p = (uint8_t)val; *str_p += 3; return true; } else if ((*str_p)[0] && !isdigit((*str_p)[0])) { *ch_p = (uint8_t)*(*str_p)++; return true; } error: *str_p = NULL; return false; /* LDNS_STATUS_SYNTAX_BAD_ESCAPE */ } INLINE bool parse_char(uint8_t *ch_p, const char** str_p) { switch (**str_p) { case '\0': return false; case '\\': *str_p += 1; return parse_escape(ch_p, str_p); default: *ch_p = (uint8_t)*(*str_p)++; return true; } } /* * No special care is taken, all dots are translated into * label seperators. * Could be made more efficient....we do 3 memcpy's in total... */ ldns_status ldns_str2rdf_dname(ldns_rdf **d, const char *str) { size_t len; const char *s; uint8_t *q, *pq, label_len; uint8_t buf[LDNS_MAX_DOMAINLEN + 1]; *d = NULL; len = strlen((char*)str); /* octet representation can make strings a lot longer than actual length */ if (len > LDNS_MAX_DOMAINLEN * 4) { return LDNS_STATUS_DOMAINNAME_OVERFLOW; } if (0 == len) { return LDNS_STATUS_DOMAINNAME_UNDERFLOW; } /* root label */ if (1 == len && *str == '.') { *d = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 1, "\0"); return LDNS_STATUS_OK; } /* get on with the rest */ /* s is on the current character in the string * pq points to where the labellength is going to go * label_len keeps track of the current label's length * q builds the dname inside the buf array */ len = 0; q = buf+1; pq = buf; label_len = 0; for (s = str; *s; s++, q++) { if (q > buf + LDNS_MAX_DOMAINLEN) { return LDNS_STATUS_DOMAINNAME_OVERFLOW; } *q = 0; switch (*s) { case '.': if (label_len > LDNS_MAX_LABELLEN) { return LDNS_STATUS_LABEL_OVERFLOW; } if (label_len == 0) { return LDNS_STATUS_EMPTY_LABEL; } len += label_len + 1; *pq = label_len; label_len = 0; pq = q; break; case '\\': /* octet value or literal char */ s += 1; if (! parse_escape(q, &s)) { return LDNS_STATUS_SYNTAX_BAD_ESCAPE; } s -= 1; label_len++; break; default: *q = (uint8_t)*s; label_len++; } } /* add root label if last char was not '.' */ if (!ldns_dname_str_absolute(str)) { if (q > buf + LDNS_MAX_DOMAINLEN) { return LDNS_STATUS_DOMAINNAME_OVERFLOW; } if (label_len > LDNS_MAX_LABELLEN) { return LDNS_STATUS_LABEL_OVERFLOW; } if (label_len == 0) { /* label_len 0 but not . at end? */ return LDNS_STATUS_EMPTY_LABEL; } len += label_len + 1; *pq = label_len; *q = 0; } len++; *d = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, len, buf); return LDNS_STATUS_OK; } ldns_status ldns_str2rdf_a(ldns_rdf **rd, const char *str) { in_addr_t address; if (inet_pton(AF_INET, (char*)str, &address) != 1) { return LDNS_STATUS_INVALID_IP4; } else { *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_A, sizeof(address), &address); } return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_aaaa(ldns_rdf **rd, const char *str) { uint8_t address[LDNS_IP6ADDRLEN + 1]; if (inet_pton(AF_INET6, (char*)str, address) != 1) { return LDNS_STATUS_INVALID_IP6; } else { *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_AAAA, sizeof(address) - 1, &address); } return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_str(ldns_rdf **rd, const char *str) { uint8_t *data, *dp, ch = 0; size_t length; /* Worst case space requirement. We'll realloc to actual size later. */ dp = data = LDNS_XMALLOC(uint8_t, strlen(str) > 255 ? 256 : (strlen(str) + 1)); if (! data) { return LDNS_STATUS_MEM_ERR; } /* Fill data (up to 255 characters) */ while (parse_char(&ch, &str)) { if (dp - data >= 255) { LDNS_FREE(data); return LDNS_STATUS_INVALID_STR; } *++dp = ch; } if (! str) { return LDNS_STATUS_SYNTAX_BAD_ESCAPE; } length = (size_t)(dp - data); /* Fix last length byte */ data[0] = (uint8_t)length; /* Lose the overmeasure */ data = LDNS_XREALLOC(dp = data, uint8_t, length + 1); if (! data) { LDNS_FREE(dp); return LDNS_STATUS_MEM_ERR; } /* Create rdf */ *rd = ldns_rdf_new(LDNS_RDF_TYPE_STR, length + 1, data); if (! *rd) { LDNS_FREE(data); return LDNS_STATUS_MEM_ERR; } return LDNS_STATUS_OK; } ldns_status ldns_str2rdf_apl(ldns_rdf **rd, const char *str) { const char *my_str = str; char *my_ip_str; size_t ip_str_len; uint16_t family; bool negation; uint8_t afdlength = 0; uint8_t *afdpart; uint8_t prefix; uint8_t *data; size_t i = 0; /* [!]afi:address/prefix */ if (strlen(my_str) < 2 || strchr(my_str, ':') == NULL || strchr(my_str, '/') == NULL || strchr(my_str, ':') > strchr(my_str, '/')) { return LDNS_STATUS_INVALID_STR; } if (my_str[0] == '!') { negation = true; my_str += 1; } else { negation = false; } family = (uint16_t) atoi(my_str); my_str = strchr(my_str, ':') + 1; /* need ip addr and only ip addr for inet_pton */ ip_str_len = (size_t) (strchr(my_str, '/') - my_str); my_ip_str = LDNS_XMALLOC(char, ip_str_len + 1); if(!my_ip_str) return LDNS_STATUS_MEM_ERR; strncpy(my_ip_str, my_str, ip_str_len + 1); my_ip_str[ip_str_len] = '\0'; if (family == 1) { /* ipv4 */ afdpart = LDNS_XMALLOC(uint8_t, 4); if(!afdpart) { LDNS_FREE(my_ip_str); return LDNS_STATUS_MEM_ERR; } if (inet_pton(AF_INET, my_ip_str, afdpart) == 0) { LDNS_FREE(my_ip_str); LDNS_FREE(afdpart); return LDNS_STATUS_INVALID_STR; } for (i = 0; i < 4; i++) { if (afdpart[i] != 0) { afdlength = i + 1; } } } else if (family == 2) { /* ipv6 */ afdpart = LDNS_XMALLOC(uint8_t, 16); if(!afdpart) { LDNS_FREE(my_ip_str); return LDNS_STATUS_MEM_ERR; } if (inet_pton(AF_INET6, my_ip_str, afdpart) == 0) { LDNS_FREE(my_ip_str); LDNS_FREE(afdpart); return LDNS_STATUS_INVALID_STR; } for (i = 0; i < 16; i++) { if (afdpart[i] != 0) { afdlength = i + 1; } } } else { /* unknown family */ LDNS_FREE(my_ip_str); return LDNS_STATUS_INVALID_STR; } my_str = strchr(my_str, '/') + 1; prefix = (uint8_t) atoi(my_str); data = LDNS_XMALLOC(uint8_t, 4 + afdlength); if(!data) { LDNS_FREE(afdpart); LDNS_FREE(my_ip_str); return LDNS_STATUS_INVALID_STR; } ldns_write_uint16(data, family); data[2] = prefix; data[3] = afdlength; if (negation) { /* set bit 1 of byte 3 */ data[3] = data[3] | 0x80; } memcpy(data + 4, afdpart, afdlength); *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_APL, afdlength + 4, data); LDNS_FREE(afdpart); LDNS_FREE(data); LDNS_FREE(my_ip_str); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_b64(ldns_rdf **rd, const char *str) { uint8_t *buffer; int16_t i; buffer = LDNS_XMALLOC(uint8_t, ldns_b64_ntop_calculate_size(strlen(str))); if(!buffer) { return LDNS_STATUS_MEM_ERR; } i = (uint16_t)ldns_b64_pton((const char*)str, buffer, ldns_b64_ntop_calculate_size(strlen(str))); if (-1 == i) { LDNS_FREE(buffer); return LDNS_STATUS_INVALID_B64; } else { *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_B64, (uint16_t) i, buffer); } LDNS_FREE(buffer); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_b32_ext(ldns_rdf **rd, const char *str) { uint8_t *buffer; int i; /* first byte contains length of actual b32 data */ uint8_t len = ldns_b32_pton_calculate_size(strlen(str)); buffer = LDNS_XMALLOC(uint8_t, len + 1); if(!buffer) { return LDNS_STATUS_MEM_ERR; } buffer[0] = len; i = ldns_b32_pton_extended_hex((const char*)str, strlen(str), buffer + 1, ldns_b32_ntop_calculate_size(strlen(str))); if (i < 0) { LDNS_FREE(buffer); return LDNS_STATUS_INVALID_B32_EXT; } else { *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_B32_EXT, (uint16_t) i + 1, buffer); } LDNS_FREE(buffer); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_hex(ldns_rdf **rd, const char *str) { uint8_t *t, *t_orig; int i; size_t len; len = strlen(str); if (len > LDNS_MAX_RDFLEN * 2) { return LDNS_STATUS_LABEL_OVERFLOW; } else { t = LDNS_XMALLOC(uint8_t, (len / 2) + 1); if(!t) { return LDNS_STATUS_MEM_ERR; } t_orig = t; /* Now process octet by octet... */ while (*str) { *t = 0; if (isspace((int) *str)) { str++; } else { for (i = 16; i >= 1; i -= 15) { while (*str && isspace((int) *str)) { str++; } if (*str) { if (isxdigit((int) *str)) { *t += ldns_hexdigit_to_int(*str) * i; } else { LDNS_FREE(t_orig); return LDNS_STATUS_ERR; } ++str; } } ++t; } } *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX, (size_t) (t - t_orig), t_orig); LDNS_FREE(t_orig); } return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_nsec(ldns_rdf **rd, const char *str) { const char *delimiters = "\n\t "; char *token = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN); ldns_buffer *str_buf; ssize_t c; uint16_t cur_type; size_t type_count = 0; ldns_rr_type type_list[65536]; if(!token) return LDNS_STATUS_MEM_ERR; if(rd == NULL) { LDNS_FREE(token); return LDNS_STATUS_NULL; } str_buf = LDNS_MALLOC(ldns_buffer); if(!str_buf) { LDNS_FREE(token); return LDNS_STATUS_MEM_ERR; } ldns_buffer_new_frm_data(str_buf, (char *)str, strlen(str)); if(ldns_buffer_status(str_buf) != LDNS_STATUS_OK) { LDNS_FREE(str_buf); LDNS_FREE(token); return LDNS_STATUS_MEM_ERR; } while ((c = ldns_bget_token(str_buf, token, delimiters, LDNS_MAX_RDFLEN)) != -1 && c != 0) { if(type_count >= sizeof(type_list)) { LDNS_FREE(str_buf); LDNS_FREE(token); return LDNS_STATUS_ERR; } cur_type = ldns_get_rr_type_by_name(token); type_list[type_count] = cur_type; type_count++; } *rd = ldns_dnssec_create_nsec_bitmap(type_list, type_count, LDNS_RR_TYPE_NSEC); LDNS_FREE(token); ldns_buffer_free(str_buf); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_type(ldns_rdf **rd, const char *str) { uint16_t type; type = htons(ldns_get_rr_type_by_name(str)); /* ldns_rr_type is a 16 bit value */ *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_TYPE, sizeof(uint16_t), &type); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_class(ldns_rdf **rd, const char *str) { uint16_t klass; klass = htons(ldns_get_rr_class_by_name(str)); /* class is 16 bit */ *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_CLASS, sizeof(uint16_t), &klass); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } /* An certificate alg field can either be specified as a 8 bits number * or by its symbolic name. Handle both */ ldns_status ldns_str2rdf_cert_alg(ldns_rdf **rd, const char *str) { ldns_lookup_table *lt; ldns_status st; uint8_t idd[2]; lt = ldns_lookup_by_name(ldns_cert_algorithms, str); st = LDNS_STATUS_OK; if (lt) { ldns_write_uint16(idd, (uint16_t) lt->id); *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_INT16, sizeof(uint16_t), idd); if (!*rd) { st = LDNS_STATUS_ERR; } } else { /* try as-is (a number) */ st = ldns_str2rdf_int16(rd, str); if (st == LDNS_STATUS_OK && ldns_rdf2native_int16(*rd) == 0) { st = LDNS_STATUS_CERT_BAD_ALGORITHM; } } return st; } static ldns_lookup_table ldns_tlsa_certificate_usages[] = { { LDNS_TLSA_USAGE_PKIX_TA , "PKIX-TA" }, { LDNS_TLSA_USAGE_PKIX_EE , "PKIX-EE" }, { LDNS_TLSA_USAGE_DANE_TA , "DANE-TA" }, { LDNS_TLSA_USAGE_DANE_EE , "DANE-EE" }, { LDNS_TLSA_USAGE_PRIVCERT , "PrivCert" } }; static ldns_lookup_table ldns_tlsa_selectors[] = { { LDNS_TLSA_SELECTOR_CERT , "Cert" }, { LDNS_TLSA_SELECTOR_SPKI , "SPKI" }, { LDNS_TLSA_SELECTOR_PRIVSEL , "PrivSel" } }; static ldns_lookup_table ldns_tlsa_matching_types[] = { { LDNS_TLSA_MATCHING_TYPE_FULL , "Full" }, { LDNS_TLSA_MATCHING_TYPE_SHA2_256 , "SHA2-256" }, { LDNS_TLSA_MATCHING_TYPE_SHA2_512 , "SHA2-512" }, { LDNS_TLSA_MATCHING_TYPE_PRIVMATCH , "PrivMatch" } }; static ldns_status ldns_str2rdf_mnemonic4int8(ldns_lookup_table *lt, ldns_rdf **rd, const char *str) { if ((lt = ldns_lookup_by_name(lt, str))) { /* it was given as a integer */ *rd = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t) lt->id); if (!*rd) return LDNS_STATUS_ERR; else return LDNS_STATUS_OK; } return ldns_str2rdf_int8(rd, str); } /* An alg field can either be specified as a 8 bits number * or by its symbolic name. Handle both */ ldns_status ldns_str2rdf_alg(ldns_rdf **rd, const char *str) { return ldns_str2rdf_mnemonic4int8(ldns_algorithms, rd, str); } ldns_status ldns_str2rdf_certificate_usage(ldns_rdf **rd, const char *str) { return ldns_str2rdf_mnemonic4int8( ldns_tlsa_certificate_usages, rd, str); } ldns_status ldns_str2rdf_selector(ldns_rdf **rd, const char *str) { return ldns_str2rdf_mnemonic4int8(ldns_tlsa_selectors, rd, str); } ldns_status ldns_str2rdf_matching_type(ldns_rdf **rd, const char *str) { return ldns_str2rdf_mnemonic4int8(ldns_tlsa_matching_types, rd, str); } ldns_status ldns_str2rdf_unknown( ATTR_UNUSED(ldns_rdf **rd) , ATTR_UNUSED(const char *str) ) { /* this should be caught in an earlier time (general str2host for rr's */ return LDNS_STATUS_NOT_IMPL; } ldns_status ldns_str2rdf_service( ATTR_UNUSED(ldns_rdf **rd) , ATTR_UNUSED(const char *str) ) { /* is this used? is this actually WKS? or SRV? */ return LDNS_STATUS_NOT_IMPL; } static int loc_parse_cm(char* my_str, char** endstr, uint8_t* m, uint8_t* e) { /* read [.][mM] */ /* into mantissa exponent format for LOC type */ uint32_t meters = 0, cm = 0, val; while (isblank(*my_str)) { my_str++; } meters = (uint32_t)strtol(my_str, &my_str, 10); if (*my_str == '.') { my_str++; cm = (uint32_t)strtol(my_str, &my_str, 10); } if (meters >= 1) { *e = 2; val = meters; } else { *e = 0; val = cm; } while(val >= 10) { (*e)++; val /= 10; } *m = (uint8_t)val; if (*e > 9) return 0; if (*my_str == 'm' || *my_str == 'M') { my_str++; } *endstr = my_str; return 1; } ldns_status ldns_str2rdf_loc(ldns_rdf **rd, const char *str) { uint32_t latitude = 0; uint32_t longitude = 0; uint32_t altitude = 0; uint8_t *data; uint32_t equator = (uint32_t) ldns_power(2, 31); uint32_t h = 0; uint32_t m = 0; uint8_t size_b = 1, size_e = 2; uint8_t horiz_pre_b = 1, horiz_pre_e = 6; uint8_t vert_pre_b = 1, vert_pre_e = 3; double s = 0.0; bool northerness; bool easterness; char *my_str = (char *) str; /* only support version 0 */ if (isdigit((int) *my_str)) { h = (uint32_t) strtol(my_str, &my_str, 10); } else { return LDNS_STATUS_INVALID_STR; } while (isblank((int) *my_str)) { my_str++; } if (isdigit((int) *my_str)) { m = (uint32_t) strtol(my_str, &my_str, 10); } else if (*my_str == 'N' || *my_str == 'S') { goto north; } else { return LDNS_STATUS_INVALID_STR; } while (isblank((int) *my_str)) { my_str++; } if (isdigit((int) *my_str)) { s = strtod(my_str, &my_str); } north: while (isblank((int) *my_str)) { my_str++; } if (*my_str == 'N') { northerness = true; } else if (*my_str == 'S') { northerness = false; } else { return LDNS_STATUS_INVALID_STR; } my_str++; /* store number */ s = 1000.0 * s; /* add a little to make floor in conversion a round */ s += 0.0005; latitude = (uint32_t) s; latitude += 1000 * 60 * m; latitude += 1000 * 60 * 60 * h; if (northerness) { latitude = equator + latitude; } else { latitude = equator - latitude; } while (isblank(*my_str)) { my_str++; } if (isdigit((int) *my_str)) { h = (uint32_t) strtol(my_str, &my_str, 10); } else { return LDNS_STATUS_INVALID_STR; } while (isblank((int) *my_str)) { my_str++; } if (isdigit((int) *my_str)) { m = (uint32_t) strtol(my_str, &my_str, 10); } else if (*my_str == 'E' || *my_str == 'W') { goto east; } else { return LDNS_STATUS_INVALID_STR; } while (isblank(*my_str)) { my_str++; } if (isdigit((int) *my_str)) { s = strtod(my_str, &my_str); } east: while (isblank(*my_str)) { my_str++; } if (*my_str == 'E') { easterness = true; } else if (*my_str == 'W') { easterness = false; } else { return LDNS_STATUS_INVALID_STR; } my_str++; /* store number */ s *= 1000.0; /* add a little to make floor in conversion a round */ s += 0.0005; longitude = (uint32_t) s; longitude += 1000 * 60 * m; longitude += 1000 * 60 * 60 * h; if (easterness) { longitude += equator; } else { longitude = equator - longitude; } altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 + 10000000.0 + 0.5); if (*my_str == 'm' || *my_str == 'M') { my_str++; } if (strlen(my_str) > 0) { if(!loc_parse_cm(my_str, &my_str, &size_b, &size_e)) return LDNS_STATUS_INVALID_STR; } if (strlen(my_str) > 0) { if(!loc_parse_cm(my_str, &my_str, &horiz_pre_b, &horiz_pre_e)) return LDNS_STATUS_INVALID_STR; } if (strlen(my_str) > 0) { if(!loc_parse_cm(my_str, &my_str, &vert_pre_b, &vert_pre_e)) return LDNS_STATUS_INVALID_STR; } data = LDNS_XMALLOC(uint8_t, 16); if(!data) { return LDNS_STATUS_MEM_ERR; } data[0] = 0; data[1] = 0; data[1] = ((size_b << 4) & 0xf0) | (size_e & 0x0f); data[2] = ((horiz_pre_b << 4) & 0xf0) | (horiz_pre_e & 0x0f); data[3] = ((vert_pre_b << 4) & 0xf0) | (vert_pre_e & 0x0f); ldns_write_uint32(data + 4, latitude); ldns_write_uint32(data + 8, longitude); ldns_write_uint32(data + 12, altitude); *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_LOC, 16, data); LDNS_FREE(data); return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_wks(ldns_rdf **rd, const char *str) { uint8_t *bitmap = NULL; uint8_t *data; int bm_len = 0; struct protoent *proto = NULL; struct servent *serv = NULL; int serv_port; ldns_buffer *str_buf; char *proto_str = NULL; char *token; if(strlen(str) == 0) token = LDNS_XMALLOC(char, 50); else token = LDNS_XMALLOC(char, strlen(str)+2); if(!token) return LDNS_STATUS_MEM_ERR; str_buf = LDNS_MALLOC(ldns_buffer); if(!str_buf) {LDNS_FREE(token); return LDNS_STATUS_MEM_ERR;} ldns_buffer_new_frm_data(str_buf, (char *)str, strlen(str)); if(ldns_buffer_status(str_buf) != LDNS_STATUS_OK) { LDNS_FREE(str_buf); LDNS_FREE(token); return LDNS_STATUS_MEM_ERR; } while(ldns_bget_token(str_buf, token, "\t\n ", strlen(str)) > 0) { if (!proto_str) { proto_str = strdup(token); if (!proto_str) { LDNS_FREE(bitmap); LDNS_FREE(token); ldns_buffer_free(str_buf); return LDNS_STATUS_INVALID_STR; } } else { serv = getservbyname(token, proto_str); if (serv) { serv_port = (int) ntohs((uint16_t) serv->s_port); } else { serv_port = atoi(token); } if (serv_port / 8 >= bm_len) { uint8_t *b2 = LDNS_XREALLOC(bitmap, uint8_t, (serv_port / 8) + 1); if(!b2) { LDNS_FREE(bitmap); LDNS_FREE(token); ldns_buffer_free(str_buf); free(proto_str); return LDNS_STATUS_INVALID_STR; } bitmap = b2; /* set to zero to be sure */ for (; bm_len <= serv_port / 8; bm_len++) { bitmap[bm_len] = 0; } } ldns_set_bit(bitmap + (serv_port / 8), 7 - (serv_port % 8), true); } } if (!proto_str || !bitmap) { LDNS_FREE(bitmap); LDNS_FREE(token); ldns_buffer_free(str_buf); free(proto_str); return LDNS_STATUS_INVALID_STR; } data = LDNS_XMALLOC(uint8_t, bm_len + 1); if(!data) { LDNS_FREE(token); ldns_buffer_free(str_buf); LDNS_FREE(bitmap); free(proto_str); return LDNS_STATUS_INVALID_STR; } if (proto_str) proto = getprotobyname(proto_str); if (proto) { data[0] = (uint8_t) proto->p_proto; } else if (proto_str) { data[0] = (uint8_t) atoi(proto_str); } memcpy(data + 1, bitmap, (size_t) bm_len); *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_WKS, (uint16_t) (bm_len + 1), data); LDNS_FREE(data); LDNS_FREE(token); ldns_buffer_free(str_buf); LDNS_FREE(bitmap); free(proto_str); #ifdef HAVE_ENDSERVENT endservent(); #endif #ifdef HAVE_ENDPROTOENT endprotoent(); #endif if(!*rd) return LDNS_STATUS_MEM_ERR; return LDNS_STATUS_OK; } ldns_status ldns_str2rdf_nsap(ldns_rdf **rd, const char *str) { size_t len, i; char* nsap_str = (char*) str; /* just a hex string with optional dots? */ if (str[0] != '0' || str[1] != 'x') { return LDNS_STATUS_INVALID_STR; } else { len = strlen(str); for (i=0; i < len; i++) { if (nsap_str[i] == '.') nsap_str[i] = ' '; } return ldns_str2rdf_hex(rd, str+2); } } ldns_status ldns_str2rdf_atma(ldns_rdf **rd, const char *str) { size_t len, i; char* atma_str = (char*) str; ldns_status status; /* just a hex string with optional dots? */ len = strlen(str); for (i=0; i < len; i++) { if (atma_str[i] == '.') atma_str[i] = ' '; } status = ldns_str2rdf_hex(rd, str); if (status != LDNS_STATUS_OK) { ; /* probably in e.164 format than */ } return status; } ldns_status ldns_str2rdf_ipseckey(ldns_rdf **rd, const char *str) { uint8_t precedence = 0; uint8_t gateway_type = 0; uint8_t algorithm = 0; char* gateway = NULL; char* publickey = NULL; uint8_t *data; ldns_buffer *str_buf; char *token; int token_count = 0; int ipseckey_len = 0; ldns_rdf* gateway_rdf = NULL; ldns_rdf* publickey_rdf = NULL; ldns_status status = LDNS_STATUS_OK; if(strlen(str) == 0) token = LDNS_XMALLOC(char, 256); else token = LDNS_XMALLOC(char, strlen(str)+2); if(!token) return LDNS_STATUS_MEM_ERR; str_buf = LDNS_MALLOC(ldns_buffer); if(!str_buf) {LDNS_FREE(token); return LDNS_STATUS_MEM_ERR;} ldns_buffer_new_frm_data(str_buf, (char *)str, strlen(str)); if(ldns_buffer_status(str_buf) != LDNS_STATUS_OK) { LDNS_FREE(str_buf); LDNS_FREE(token); return LDNS_STATUS_MEM_ERR; } while(ldns_bget_token(str_buf, token, "\t\n ", strlen(str)) > 0) { switch (token_count) { case 0: precedence = (uint8_t)atoi(token); break; case 1: gateway_type = (uint8_t)atoi(token); break; case 2: algorithm = (uint8_t)atoi(token); break; case 3: gateway = strdup(token); if (!gateway || (gateway_type == 0 && (token[0] != '.' || token[1] != '\0'))) { LDNS_FREE(gateway); LDNS_FREE(token); ldns_buffer_free(str_buf); return LDNS_STATUS_INVALID_STR; } break; case 4: publickey = strdup(token); break; default: LDNS_FREE(token); ldns_buffer_free(str_buf); return LDNS_STATUS_INVALID_STR; break; } token_count++; } if (!gateway || !publickey) { if (gateway) LDNS_FREE(gateway); if (publickey) LDNS_FREE(publickey); LDNS_FREE(token); ldns_buffer_free(str_buf); return LDNS_STATUS_INVALID_STR; } if (gateway_type == 1) { status = ldns_str2rdf_a(&gateway_rdf, gateway); } else if (gateway_type == 2) { status = ldns_str2rdf_aaaa(&gateway_rdf, gateway); } else if (gateway_type == 3) { status = ldns_str2rdf_dname(&gateway_rdf, gateway); } if (status != LDNS_STATUS_OK) { if (gateway) LDNS_FREE(gateway); if (publickey) LDNS_FREE(publickey); LDNS_FREE(token); ldns_buffer_free(str_buf); return LDNS_STATUS_INVALID_STR; } status = ldns_str2rdf_b64(&publickey_rdf, publickey); if (status != LDNS_STATUS_OK) { if (gateway) LDNS_FREE(gateway); if (publickey) LDNS_FREE(publickey); LDNS_FREE(token); ldns_buffer_free(str_buf); if (gateway_rdf) ldns_rdf_free(gateway_rdf); return LDNS_STATUS_INVALID_STR; } /* now copy all into one ipseckey rdf */ if (gateway_type) ipseckey_len = 3 + (int)ldns_rdf_size(gateway_rdf) + (int)ldns_rdf_size(publickey_rdf); else ipseckey_len = 3 + (int)ldns_rdf_size(publickey_rdf); data = LDNS_XMALLOC(uint8_t, ipseckey_len); if(!data) { if (gateway) LDNS_FREE(gateway); if (publickey) LDNS_FREE(publickey); LDNS_FREE(token); ldns_buffer_free(str_buf); if (gateway_rdf) ldns_rdf_free(gateway_rdf); if (publickey_rdf) ldns_rdf_free(publickey_rdf); return LDNS_STATUS_MEM_ERR; } data[0] = precedence; data[1] = gateway_type; data[2] = algorithm; if (gateway_type) { memcpy(data + 3, ldns_rdf_data(gateway_rdf), ldns_rdf_size(gateway_rdf)); memcpy(data + 3 + ldns_rdf_size(gateway_rdf), ldns_rdf_data(publickey_rdf), ldns_rdf_size(publickey_rdf)); } else { memcpy(data + 3, ldns_rdf_data(publickey_rdf), ldns_rdf_size(publickey_rdf)); } *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_IPSECKEY, (uint16_t) ipseckey_len, data); if (gateway) LDNS_FREE(gateway); if (publickey) LDNS_FREE(publickey); LDNS_FREE(token); ldns_buffer_free(str_buf); ldns_rdf_free(gateway_rdf); ldns_rdf_free(publickey_rdf); LDNS_FREE(data); if(!*rd) return LDNS_STATUS_MEM_ERR; return LDNS_STATUS_OK; } ldns_status ldns_str2rdf_ilnp64(ldns_rdf **rd, const char *str) { unsigned int a, b, c, d; uint16_t shorts[4]; int l; if (sscanf(str, "%4x:%4x:%4x:%4x%n", &a, &b, &c, &d, &l) != 4 || l != (int)strlen(str) || /* more data to read */ strpbrk(str, "+-") /* signed hexes */ ) { return LDNS_STATUS_INVALID_ILNP64; } else { shorts[0] = htons(a); shorts[1] = htons(b); shorts[2] = htons(c); shorts[3] = htons(d); *rd = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_ILNP64, 4 * sizeof(uint16_t), &shorts); } return *rd ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_eui48(ldns_rdf **rd, const char *str) { unsigned int a, b, c, d, e, f; uint8_t bytes[6]; int l; if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x%n", &a, &b, &c, &d, &e, &f, &l) != 6 || l != (int)strlen(str)) { return LDNS_STATUS_INVALID_EUI48; } else { bytes[0] = a; bytes[1] = b; bytes[2] = c; bytes[3] = d; bytes[4] = e; bytes[5] = f; *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_EUI48, 6, &bytes); } return *rd ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_eui64(ldns_rdf **rd, const char *str) { unsigned int a, b, c, d, e, f, g, h; uint8_t bytes[8]; int l; if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n", &a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 || l != (int)strlen(str)) { return LDNS_STATUS_INVALID_EUI64; } else { bytes[0] = a; bytes[1] = b; bytes[2] = c; bytes[3] = d; bytes[4] = e; bytes[5] = f; bytes[6] = g; bytes[7] = h; *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_EUI64, 8, &bytes); } return *rd ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; } ldns_status ldns_str2rdf_tag(ldns_rdf **rd, const char *str) { uint8_t *data; const char* ptr; if (strlen(str) > 255) { return LDNS_STATUS_INVALID_TAG; } for (ptr = str; *ptr; ptr++) { if (! isalnum(*ptr)) { return LDNS_STATUS_INVALID_TAG; } } data = LDNS_XMALLOC(uint8_t, strlen(str) + 1); if (!data) { return LDNS_STATUS_MEM_ERR; } data[0] = strlen(str); memcpy(data + 1, str, strlen(str)); *rd = ldns_rdf_new(LDNS_RDF_TYPE_TAG, strlen(str) + 1, data); if (!*rd) { LDNS_FREE(data); return LDNS_STATUS_MEM_ERR; } return LDNS_STATUS_OK; } ldns_status ldns_str2rdf_long_str(ldns_rdf **rd, const char *str) { uint8_t *data, *dp, ch = 0; size_t length; /* Worst case space requirement. We'll realloc to actual size later. */ dp = data = LDNS_XMALLOC(uint8_t, strlen(str)); if (! data) { return LDNS_STATUS_MEM_ERR; } /* Fill data with parsed bytes */ while (parse_char(&ch, &str)) { *dp++ = ch; if (dp - data > LDNS_MAX_RDFLEN) { LDNS_FREE(data); return LDNS_STATUS_INVALID_STR; } } if (! str) { return LDNS_STATUS_SYNTAX_BAD_ESCAPE; } length = (size_t)(dp - data); /* Lose the overmeasure */ data = LDNS_XREALLOC(dp = data, uint8_t, length); if (! data) { LDNS_FREE(dp); return LDNS_STATUS_MEM_ERR; } /* Create rdf */ *rd = ldns_rdf_new(LDNS_RDF_TYPE_LONG_STR, length, data); if (! *rd) { LDNS_FREE(data); return LDNS_STATUS_MEM_ERR; } return LDNS_STATUS_OK; } ldns_status ldns_str2rdf_hip(ldns_rdf **rd, const char *str) { const char *hit = strchr(str, ' ') + 1; const char *pk = hit == NULL ? NULL : strchr(hit, ' ') + 1; size_t hit_size = hit == NULL ? 0 : pk == NULL ? strlen(hit) : (size_t) (pk - hit) - 1; size_t pk_size = pk == NULL ? 0 : strlen(pk); size_t hit_wire_size = (hit_size + 1) / 2; size_t pk_wire_size = ldns_b64_pton_calculate_size(pk_size); size_t rdf_size = 4 + hit_wire_size + pk_wire_size; char *endptr; /* utility var for strtol usage */ int algorithm = strtol(str, &endptr, 10); uint8_t *data, *dp; int hi, lo, written; if (hit_size == 0 || pk_size == 0 || (hit_size + 1) / 2 > 255 || rdf_size > LDNS_MAX_RDFLEN || algorithm < 0 || algorithm > 255 || (errno != 0 && algorithm == 0) /* out of range */ || endptr == str /* no digits */) { return LDNS_STATUS_SYNTAX_ERR; } if ((data = LDNS_XMALLOC(uint8_t, rdf_size)) == NULL) { return LDNS_STATUS_MEM_ERR; } /* From RFC 5205 section 5. HIP RR Storage Format: ************************************************* 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | HIT length | PK algorithm | PK length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | ~ HIT ~ | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | +-+-+-+-+-+-+-+-+-+-+-+ + | Public Key | ~ ~ | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | ~ Rendezvous Servers ~ | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +-+-+-+-+-+-+-+ */ data[0] = (uint8_t) hit_wire_size; data[1] = (uint8_t) algorithm; for (dp = data + 4; *hit && *hit != ' '; dp++) { if ((hi = ldns_hexdigit_to_int(*hit++)) == -1 || (lo = ldns_hexdigit_to_int(*hit++)) == -1) { LDNS_FREE(data); return LDNS_STATUS_INVALID_HEX; } *dp = (uint8_t) hi << 4 | lo; } if ((written = ldns_b64_pton(pk, dp, pk_wire_size)) <= 0) { LDNS_FREE(data); return LDNS_STATUS_INVALID_B64; } /* Because ldns_b64_pton_calculate_size isn't always correct: * (we have to fix it at some point) */ pk_wire_size = (uint16_t) written; ldns_write_uint16(data + 2, pk_wire_size); rdf_size = 4 + hit_wire_size + pk_wire_size; /* Create rdf */ if (! (*rd = ldns_rdf_new(LDNS_RDF_TYPE_HIP, rdf_size, data))) { LDNS_FREE(data); return LDNS_STATUS_MEM_ERR; } return LDNS_STATUS_OK; } Net-LDNS-0.75/src/ldns/tsig.c000644 000770 000024 00000027147 12471046240 016170 0ustar00calledstaff000000 000000 /* * tsig.c * * contains the functions needed for TSIG [RFC2845] * * (c) 2005-2006 NLnet Labs * See the file LICENSE for the license */ #include #include #include #ifdef HAVE_SSL #include #include #endif /* HAVE_SSL */ char * ldns_tsig_algorithm(ldns_tsig_credentials *tc) { return tc->algorithm; } char * ldns_tsig_keyname(ldns_tsig_credentials *tc) { return tc->keyname; } char * ldns_tsig_keydata(ldns_tsig_credentials *tc) { return tc->keydata; } char * ldns_tsig_keyname_clone(ldns_tsig_credentials *tc) { return strdup(tc->keyname); } char * ldns_tsig_keydata_clone(ldns_tsig_credentials *tc) { return strdup(tc->keydata); } /* * Makes an exact copy of the wire, but with the tsig rr removed */ static uint8_t * ldns_tsig_prepare_pkt_wire(uint8_t *wire, size_t wire_len, size_t *result_len) { uint8_t *wire2 = NULL; uint16_t qd_count; uint16_t an_count; uint16_t ns_count; uint16_t ar_count; ldns_rr *rr; size_t pos; uint16_t i; ldns_status status; if(wire_len < LDNS_HEADER_SIZE) { return NULL; } /* fake parse the wire */ qd_count = LDNS_QDCOUNT(wire); an_count = LDNS_ANCOUNT(wire); ns_count = LDNS_NSCOUNT(wire); ar_count = LDNS_ARCOUNT(wire); if (ar_count > 0) { ar_count--; } else { return NULL; } pos = LDNS_HEADER_SIZE; for (i = 0; i < qd_count; i++) { status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_QUESTION); if (status != LDNS_STATUS_OK) { return NULL; } ldns_rr_free(rr); } for (i = 0; i < an_count; i++) { status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_ANSWER); if (status != LDNS_STATUS_OK) { return NULL; } ldns_rr_free(rr); } for (i = 0; i < ns_count; i++) { status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_AUTHORITY); if (status != LDNS_STATUS_OK) { return NULL; } ldns_rr_free(rr); } for (i = 0; i < ar_count; i++) { status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_ADDITIONAL); if (status != LDNS_STATUS_OK) { return NULL; } ldns_rr_free(rr); } *result_len = pos; wire2 = LDNS_XMALLOC(uint8_t, *result_len); if(!wire2) { return NULL; } memcpy(wire2, wire, *result_len); ldns_write_uint16(wire2 + LDNS_ARCOUNT_OFF, ar_count); return wire2; } #ifdef HAVE_SSL static const EVP_MD * ldns_digest_function(char *name) { /* these are the mandatory algorithms from RFC4635 */ /* The optional algorithms are not yet implemented */ if (strcasecmp(name, "hmac-sha256.") == 0) { #ifdef HAVE_EVP_SHA256 return EVP_sha256(); #else return NULL; #endif } else if (strcasecmp(name, "hmac-sha1.") == 0) { return EVP_sha1(); } else if (strcasecmp(name, "hmac-md5.sig-alg.reg.int.") == 0) { return EVP_md5(); } else { return NULL; } } #endif #ifdef HAVE_SSL static ldns_status ldns_tsig_mac_new(ldns_rdf **tsig_mac, uint8_t *pkt_wire, size_t pkt_wire_size, const char *key_data, ldns_rdf *key_name_rdf, ldns_rdf *fudge_rdf, ldns_rdf *algorithm_rdf, ldns_rdf *time_signed_rdf, ldns_rdf *error_rdf, ldns_rdf *other_data_rdf, ldns_rdf *orig_mac_rdf, int tsig_timers_only) { ldns_status status; char *wireformat; int wiresize; unsigned char *mac_bytes = NULL; unsigned char *key_bytes = NULL; int key_size; const EVP_MD *digester; char *algorithm_name = NULL; unsigned int md_len = EVP_MAX_MD_SIZE; ldns_rdf *result = NULL; ldns_buffer *data_buffer = NULL; ldns_rdf *canonical_key_name_rdf = NULL; ldns_rdf *canonical_algorithm_rdf = NULL; if (key_name_rdf == NULL || algorithm_rdf == NULL) { return LDNS_STATUS_NULL; } canonical_key_name_rdf = ldns_rdf_clone(key_name_rdf); if (canonical_key_name_rdf == NULL) { return LDNS_STATUS_MEM_ERR; } canonical_algorithm_rdf = ldns_rdf_clone(algorithm_rdf); if (canonical_algorithm_rdf == NULL) { ldns_rdf_deep_free(canonical_key_name_rdf); return LDNS_STATUS_MEM_ERR; } /* * prepare the digestable information */ data_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!data_buffer) { status = LDNS_STATUS_MEM_ERR; goto clean; } /* if orig_mac is not NULL, add it too */ if (orig_mac_rdf) { (void) ldns_rdf2buffer_wire(data_buffer, orig_mac_rdf); } ldns_buffer_write(data_buffer, pkt_wire, pkt_wire_size); if (!tsig_timers_only) { ldns_dname2canonical(canonical_key_name_rdf); (void)ldns_rdf2buffer_wire(data_buffer, canonical_key_name_rdf); ldns_buffer_write_u16(data_buffer, LDNS_RR_CLASS_ANY); ldns_buffer_write_u32(data_buffer, 0); ldns_dname2canonical(canonical_algorithm_rdf); (void)ldns_rdf2buffer_wire(data_buffer, canonical_algorithm_rdf); } (void)ldns_rdf2buffer_wire(data_buffer, time_signed_rdf); (void)ldns_rdf2buffer_wire(data_buffer, fudge_rdf); if (!tsig_timers_only) { (void)ldns_rdf2buffer_wire(data_buffer, error_rdf); (void)ldns_rdf2buffer_wire(data_buffer, other_data_rdf); } wireformat = (char *) data_buffer->_data; wiresize = (int) ldns_buffer_position(data_buffer); algorithm_name = ldns_rdf2str(algorithm_rdf); if(!algorithm_name) { status = LDNS_STATUS_MEM_ERR; goto clean; } /* prepare the key */ key_bytes = LDNS_XMALLOC(unsigned char, ldns_b64_pton_calculate_size(strlen(key_data))); if(!key_bytes) { status = LDNS_STATUS_MEM_ERR; goto clean; } key_size = ldns_b64_pton(key_data, key_bytes, ldns_b64_pton_calculate_size(strlen(key_data))); if (key_size < 0) { status = LDNS_STATUS_INVALID_B64; goto clean; } /* hmac it */ /* 2 spare bytes for the length */ mac_bytes = LDNS_XMALLOC(unsigned char, md_len+2); if(!mac_bytes) { status = LDNS_STATUS_MEM_ERR; goto clean; } memset(mac_bytes, 0, md_len+2); digester = ldns_digest_function(algorithm_name); if (digester) { (void) HMAC(digester, key_bytes, key_size, (void *)wireformat, (size_t) wiresize, mac_bytes + 2, &md_len); ldns_write_uint16(mac_bytes, md_len); result = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT16_DATA, md_len + 2, mac_bytes); } else { status = LDNS_STATUS_CRYPTO_UNKNOWN_ALGO; goto clean; } *tsig_mac = result; status = LDNS_STATUS_OK; clean: LDNS_FREE(mac_bytes); LDNS_FREE(key_bytes); LDNS_FREE(algorithm_name); ldns_buffer_free(data_buffer); ldns_rdf_deep_free(canonical_algorithm_rdf); ldns_rdf_deep_free(canonical_key_name_rdf); return status; } #endif /* HAVE_SSL */ #ifdef HAVE_SSL bool ldns_pkt_tsig_verify(ldns_pkt *pkt, uint8_t *wire, size_t wirelen, const char *key_name, const char *key_data, ldns_rdf *orig_mac_rdf) { return ldns_pkt_tsig_verify_next(pkt, wire, wirelen, key_name, key_data, orig_mac_rdf, 0); } bool ldns_pkt_tsig_verify_next(ldns_pkt *pkt, uint8_t *wire, size_t wirelen, const char* key_name, const char *key_data, ldns_rdf *orig_mac_rdf, int tsig_timers_only) { ldns_rdf *fudge_rdf; ldns_rdf *algorithm_rdf; ldns_rdf *time_signed_rdf; ldns_rdf *orig_id_rdf; ldns_rdf *error_rdf; ldns_rdf *other_data_rdf; ldns_rdf *pkt_mac_rdf; ldns_rdf *my_mac_rdf; ldns_rdf *key_name_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, key_name); uint16_t pkt_id, orig_pkt_id; ldns_status status; uint8_t *prepared_wire = NULL; size_t prepared_wire_size = 0; ldns_rr *orig_tsig = ldns_pkt_tsig(pkt); if (!orig_tsig || ldns_rr_rd_count(orig_tsig) <= 6) { ldns_rdf_deep_free(key_name_rdf); return false; } algorithm_rdf = ldns_rr_rdf(orig_tsig, 0); time_signed_rdf = ldns_rr_rdf(orig_tsig, 1); fudge_rdf = ldns_rr_rdf(orig_tsig, 2); pkt_mac_rdf = ldns_rr_rdf(orig_tsig, 3); orig_id_rdf = ldns_rr_rdf(orig_tsig, 4); error_rdf = ldns_rr_rdf(orig_tsig, 5); other_data_rdf = ldns_rr_rdf(orig_tsig, 6); /* remove temporarily */ ldns_pkt_set_tsig(pkt, NULL); /* temporarily change the id to the original id */ pkt_id = ldns_pkt_id(pkt); orig_pkt_id = ldns_rdf2native_int16(orig_id_rdf); ldns_pkt_set_id(pkt, orig_pkt_id); prepared_wire = ldns_tsig_prepare_pkt_wire(wire, wirelen, &prepared_wire_size); status = ldns_tsig_mac_new(&my_mac_rdf, prepared_wire, prepared_wire_size, key_data, key_name_rdf, fudge_rdf, algorithm_rdf, time_signed_rdf, error_rdf, other_data_rdf, orig_mac_rdf, tsig_timers_only); LDNS_FREE(prepared_wire); if (status != LDNS_STATUS_OK) { ldns_rdf_deep_free(key_name_rdf); return false; } /* Put back the values */ ldns_pkt_set_tsig(pkt, orig_tsig); ldns_pkt_set_id(pkt, pkt_id); ldns_rdf_deep_free(key_name_rdf); if (ldns_rdf_compare(pkt_mac_rdf, my_mac_rdf) == 0) { ldns_rdf_deep_free(my_mac_rdf); return true; } else { ldns_rdf_deep_free(my_mac_rdf); return false; } } #endif /* HAVE_SSL */ #ifdef HAVE_SSL ldns_status ldns_pkt_tsig_sign(ldns_pkt *pkt, const char *key_name, const char *key_data, uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac) { return ldns_pkt_tsig_sign_next(pkt, key_name, key_data, fudge, algorithm_name, query_mac, 0); } ldns_status ldns_pkt_tsig_sign_next(ldns_pkt *pkt, const char *key_name, const char *key_data, uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac, int tsig_timers_only) { ldns_rr *tsig_rr; ldns_rdf *key_name_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, key_name); ldns_rdf *fudge_rdf = NULL; ldns_rdf *orig_id_rdf = NULL; ldns_rdf *algorithm_rdf; ldns_rdf *error_rdf = NULL; ldns_rdf *mac_rdf = NULL; ldns_rdf *other_data_rdf = NULL; ldns_status status = LDNS_STATUS_OK; uint8_t *pkt_wire = NULL; size_t pkt_wire_len; struct timeval tv_time_signed; uint8_t *time_signed = NULL; ldns_rdf *time_signed_rdf = NULL; algorithm_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, algorithm_name); if(!key_name_rdf || !algorithm_rdf) { status = LDNS_STATUS_MEM_ERR; goto clean; } /* eww don't have create tsigtime rdf yet :( */ /* bleh :p */ if (gettimeofday(&tv_time_signed, NULL) == 0) { time_signed = LDNS_XMALLOC(uint8_t, 6); if(!time_signed) { status = LDNS_STATUS_MEM_ERR; goto clean; } ldns_write_uint64_as_uint48(time_signed, (uint64_t)tv_time_signed.tv_sec); } else { status = LDNS_STATUS_INTERNAL_ERR; goto clean; } time_signed_rdf = ldns_rdf_new(LDNS_RDF_TYPE_TSIGTIME, 6, time_signed); if(!time_signed_rdf) { LDNS_FREE(time_signed); status = LDNS_STATUS_MEM_ERR; goto clean; } fudge_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, fudge); orig_id_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, ldns_pkt_id(pkt)); error_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, 0); other_data_rdf = ldns_native2rdf_int16_data(0, NULL); if(!fudge_rdf || !orig_id_rdf || !error_rdf || !other_data_rdf) { status = LDNS_STATUS_MEM_ERR; goto clean; } if (ldns_pkt2wire(&pkt_wire, pkt, &pkt_wire_len) != LDNS_STATUS_OK) { status = LDNS_STATUS_ERR; goto clean; } status = ldns_tsig_mac_new(&mac_rdf, pkt_wire, pkt_wire_len, key_data, key_name_rdf, fudge_rdf, algorithm_rdf, time_signed_rdf, error_rdf, other_data_rdf, query_mac, tsig_timers_only); if (!mac_rdf) { goto clean; } LDNS_FREE(pkt_wire); /* Create the TSIG RR */ tsig_rr = ldns_rr_new(); if(!tsig_rr) { status = LDNS_STATUS_MEM_ERR; goto clean; } ldns_rr_set_owner(tsig_rr, key_name_rdf); ldns_rr_set_class(tsig_rr, LDNS_RR_CLASS_ANY); ldns_rr_set_type(tsig_rr, LDNS_RR_TYPE_TSIG); ldns_rr_set_ttl(tsig_rr, 0); ldns_rr_push_rdf(tsig_rr, algorithm_rdf); ldns_rr_push_rdf(tsig_rr, time_signed_rdf); ldns_rr_push_rdf(tsig_rr, fudge_rdf); ldns_rr_push_rdf(tsig_rr, mac_rdf); ldns_rr_push_rdf(tsig_rr, orig_id_rdf); ldns_rr_push_rdf(tsig_rr, error_rdf); ldns_rr_push_rdf(tsig_rr, other_data_rdf); ldns_pkt_set_tsig(pkt, tsig_rr); return status; clean: LDNS_FREE(pkt_wire); ldns_rdf_free(key_name_rdf); ldns_rdf_free(algorithm_rdf); ldns_rdf_free(time_signed_rdf); ldns_rdf_free(fudge_rdf); ldns_rdf_free(orig_id_rdf); ldns_rdf_free(error_rdf); ldns_rdf_free(other_data_rdf); return status; } #endif /* HAVE_SSL */ Net-LDNS-0.75/src/ldns/update.c000644 000770 000024 00000017026 12471046240 016477 0ustar00calledstaff000000 000000 /* update.c * * Functions for RFC 2136 Dynamic Update * * Copyright (c) 2005-2008, NLnet Labs. All rights reserved. * * See LICENSE for the license. */ #include #include #include #include #include /* * RFC 2136 sections mapped to RFC 1035: * zone/ZO -- QD/question * prerequisites/PR -- AN/answers * updates/UP -- NS/authority records * additional data/AD -- AR/additional records */ ldns_pkt * ldns_update_pkt_new(ldns_rdf *zone_rdf, ldns_rr_class c, ldns_rr_list *pr_rrlist, ldns_rr_list *up_rrlist, ldns_rr_list *ad_rrlist) { ldns_pkt *p; if (!zone_rdf || !up_rrlist) { return NULL; } if (c == 0) { c = LDNS_RR_CLASS_IN; } /* Create packet, fill in Zone Section. */ p = ldns_pkt_query_new(zone_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD); if (!p) { return NULL; } zone_rdf = NULL; /* No longer safe to use. */ ldns_pkt_set_opcode(p, LDNS_PACKET_UPDATE); ldns_rr_list_deep_free(p->_authority); ldns_pkt_set_authority(p, ldns_rr_list_clone(up_rrlist)); ldns_update_set_upcount(p, ldns_rr_list_rr_count(up_rrlist)); if (pr_rrlist) { ldns_rr_list_deep_free(p->_answer); /*XXX access function */ ldns_pkt_set_answer(p, ldns_rr_list_clone(pr_rrlist)); ldns_update_set_prcount(p, ldns_rr_list_rr_count(pr_rrlist)); } if (ad_rrlist) { ldns_rr_list_deep_free(p->_additional); ldns_pkt_set_additional(p, ldns_rr_list_clone(ad_rrlist)); ldns_update_set_adcount(p, ldns_rr_list_rr_count(ad_rrlist)); } return p; } ldns_status ldns_update_pkt_tsig_add(ldns_pkt *p, ldns_resolver *r) { #ifdef HAVE_SSL uint16_t fudge = 300; /* Recommended fudge. [RFC2845 6.4] */ if (ldns_resolver_tsig_keyname(r) && ldns_resolver_tsig_keydata(r)) return ldns_pkt_tsig_sign(p, ldns_resolver_tsig_keyname(r), ldns_resolver_tsig_keydata(r), fudge, ldns_resolver_tsig_algorithm(r), NULL); #else /* do nothing */ (void)p; (void)r; #endif /* HAVE_SSL */ /* No TSIG to do. */ return LDNS_STATUS_OK; } /* Move to higher.c or similar? */ /* XXX doc */ ldns_status ldns_update_soa_mname(ldns_rdf *zone, ldns_resolver *r, ldns_rr_class c, ldns_rdf **mname) { ldns_rr *soa_rr; ldns_pkt *query, *resp; /* Nondestructive, so clone 'zone' here */ query = ldns_pkt_query_new(ldns_rdf_clone(zone), LDNS_RR_TYPE_SOA, c, LDNS_RD); if (!query) { return LDNS_STATUS_ERR; } ldns_pkt_set_random_id(query); if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) { ldns_pkt_free(query); return LDNS_STATUS_ERR; } ldns_pkt_free(query); if (!resp) { return LDNS_STATUS_ERR; } /* Expect a SOA answer. */ *mname = NULL; while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_answer(resp)))) { if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA || ldns_rr_rdf(soa_rr, 0) == NULL) continue; /* [RFC1035 3.3.13] */ *mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0)); break; } ldns_pkt_free(resp); return *mname ? LDNS_STATUS_OK : LDNS_STATUS_ERR; } /* Try to get zone and MNAME from SOA queries. */ ldns_status ldns_update_soa_zone_mname(const char *fqdn, ldns_resolver *r, ldns_rr_class c, ldns_rdf **zone_rdf, ldns_rdf **mname_rdf) { ldns_rr *soa_rr, *rr; ldns_rdf *soa_zone = NULL, *soa_mname = NULL; ldns_rdf *ipaddr, *fqdn_rdf, *tmp; ldns_rdf **nslist; ldns_pkt *query, *resp; ldns_resolver *tmp_r; size_t i; /* * XXX Ok, this cannot be the best way to find this...? * XXX (I run into weird cache-related stuff here) */ /* Step 1 - first find a nameserver that should know *something* */ fqdn_rdf = ldns_dname_new_frm_str(fqdn); query = ldns_pkt_query_new(fqdn_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD); if (!query) { return LDNS_STATUS_ERR; } fqdn_rdf = NULL; ldns_pkt_set_random_id(query); if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) { ldns_pkt_free(query); return LDNS_STATUS_ERR; } ldns_pkt_free(query); if (!resp) { return LDNS_STATUS_ERR; } /* XXX Is it safe to only look in authority section here? */ while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_authority(resp)))) { if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA || ldns_rr_rdf(soa_rr, 0) == NULL) continue; /* [RFC1035 3.3.13] */ soa_mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0)); break; } ldns_pkt_free(resp); if (!soa_rr) { return LDNS_STATUS_ERR; } /* Step 2 - find SOA MNAME IP address, add to resolver */ query = ldns_pkt_query_new(soa_mname, LDNS_RR_TYPE_A, c, LDNS_RD); if (!query) { return LDNS_STATUS_ERR; } soa_mname = NULL; ldns_pkt_set_random_id(query); if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) { ldns_pkt_free(query); return LDNS_STATUS_ERR; } ldns_pkt_free(query); if (!resp) { return LDNS_STATUS_ERR; } if (ldns_pkt_ancount(resp) == 0) { ldns_pkt_free(resp); return LDNS_STATUS_ERR; } /* XXX There may be more than one answer RR here. */ rr = ldns_rr_list_pop_rr(ldns_pkt_answer(resp)); ipaddr = ldns_rr_rdf(rr, 0); /* Put the SOA mname IP first in the nameserver list. */ if (!(tmp_r = ldns_resolver_clone(r))) { return LDNS_STATUS_MEM_ERR; } nslist = ldns_resolver_nameservers(tmp_r); for (i = 0; i < ldns_resolver_nameserver_count(tmp_r); i++) { if (ldns_rdf_compare(ipaddr, nslist[i]) == 0) { if (i) { tmp = nslist[0]; nslist[0] = nslist[i]; nslist[i] = tmp; } break; } } if (i >= ldns_resolver_nameserver_count(tmp_r)) { /* SOA mname was not part of the resolver so add it first. */ (void) ldns_resolver_push_nameserver(tmp_r, ipaddr); nslist = ldns_resolver_nameservers(tmp_r); i = ldns_resolver_nameserver_count(tmp_r) - 1; tmp = nslist[0]; nslist[0] = nslist[i]; nslist[i] = tmp; } ldns_pkt_free(resp); /* Make sure to ask the first in the list, i.e SOA mname */ ldns_resolver_set_random(tmp_r, false); /* Step 3 - Redo SOA query, sending to SOA MNAME directly. */ fqdn_rdf = ldns_dname_new_frm_str(fqdn); query = ldns_pkt_query_new(fqdn_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD); if (!query) { ldns_resolver_free(tmp_r); return LDNS_STATUS_ERR; } fqdn_rdf = NULL; ldns_pkt_set_random_id(query); if (ldns_resolver_send_pkt(&resp, tmp_r, query) != LDNS_STATUS_OK) { ldns_pkt_free(query); ldns_resolver_free(tmp_r); return LDNS_STATUS_ERR; } ldns_resolver_free(tmp_r); ldns_pkt_free(query); if (!resp) { return LDNS_STATUS_ERR; } /* XXX Is it safe to only look in authority section here, too? */ while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_authority(resp)))) { if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA || ldns_rr_rdf(soa_rr, 0) == NULL) continue; /* [RFC1035 3.3.13] */ soa_mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0)); soa_zone = ldns_rdf_clone(ldns_rr_owner(soa_rr)); break; } ldns_pkt_free(resp); if (!soa_rr) { return LDNS_STATUS_ERR; } /* That seems to have worked, pass results to caller. */ *zone_rdf = soa_zone; *mname_rdf = soa_mname; return LDNS_STATUS_OK; } /* * ldns_update_{get,set}_{zo,pr,up,ad}count */ uint16_t ldns_update_zocount(const ldns_pkt *p) { return ldns_pkt_qdcount(p); } uint16_t ldns_update_prcount(const ldns_pkt *p) { return ldns_pkt_ancount(p); } uint16_t ldns_update_upcount(const ldns_pkt *p) { return ldns_pkt_nscount(p); } uint16_t ldns_update_ad(const ldns_pkt *p) { return ldns_pkt_arcount(p); } void ldns_update_set_zo(ldns_pkt *p, uint16_t v) { ldns_pkt_set_qdcount(p, v); } void ldns_update_set_prcount(ldns_pkt *p, uint16_t v) { ldns_pkt_set_ancount(p, v); } void ldns_update_set_upcount(ldns_pkt *p, uint16_t v) { ldns_pkt_set_nscount(p, v); } void ldns_update_set_adcount(ldns_pkt *p, uint16_t v) { ldns_pkt_set_arcount(p, v); } Net-LDNS-0.75/src/ldns/util.c000644 000770 000024 00000043226 12471046240 016173 0ustar00calledstaff000000 000000 /* * util.c * * some general memory functions * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SSL #include #endif ldns_lookup_table * ldns_lookup_by_name(ldns_lookup_table *table, const char *name) { while (table->name != NULL) { if (strcasecmp(name, table->name) == 0) return table; table++; } return NULL; } ldns_lookup_table * ldns_lookup_by_id(ldns_lookup_table *table, int id) { while (table->name != NULL) { if (table->id == id) return table; table++; } return NULL; } int ldns_get_bit(uint8_t bits[], size_t index) { /* * The bits are counted from left to right, so bit #0 is the * left most bit. */ return (int) (bits[index / 8] & (1 << (7 - index % 8))); } int ldns_get_bit_r(uint8_t bits[], size_t index) { /* * The bits are counted from right to left, so bit #0 is the * right most bit. */ return (int) bits[index / 8] & (1 << (index % 8)); } void ldns_set_bit(uint8_t *byte, int bit_nr, bool value) { /* * The bits are counted from right to left, so bit #0 is the * right most bit. */ if (bit_nr >= 0 && bit_nr < 8) { if (value) { *byte = *byte | (0x01 << bit_nr); } else { *byte = *byte & ~(0x01 << bit_nr); } } } int ldns_hexdigit_to_int(char ch) { switch (ch) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': case 'A': return 10; case 'b': case 'B': return 11; case 'c': case 'C': return 12; case 'd': case 'D': return 13; case 'e': case 'E': return 14; case 'f': case 'F': return 15; default: return -1; } } char ldns_int_to_hexdigit(int i) { switch (i) { case 0: return '0'; case 1: return '1'; case 2: return '2'; case 3: return '3'; case 4: return '4'; case 5: return '5'; case 6: return '6'; case 7: return '7'; case 8: return '8'; case 9: return '9'; case 10: return 'a'; case 11: return 'b'; case 12: return 'c'; case 13: return 'd'; case 14: return 'e'; case 15: return 'f'; default: abort(); } } int ldns_hexstring_to_data(uint8_t *data, const char *str) { size_t i; if (!str || !data) { return -1; } if (strlen(str) % 2 != 0) { return -2; } for (i = 0; i < strlen(str) / 2; i++) { data[i] = 16 * (uint8_t) ldns_hexdigit_to_int(str[i*2]) + (uint8_t) ldns_hexdigit_to_int(str[i*2 + 1]); } return (int) i; } const char * ldns_version(void) { return (char*)LDNS_VERSION; } /* Number of days per month (except for February in leap years). */ static const int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; #define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y))) #define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) - 1 ) : ((x) / (y))) static int is_leap_year(int year) { return LDNS_MOD(year, 4) == 0 && (LDNS_MOD(year, 100) != 0 || LDNS_MOD(year, 400) == 0); } static int leap_days(int y1, int y2) { --y1; --y2; return (LDNS_DIV(y2, 4) - LDNS_DIV(y1, 4)) - (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) + (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400)); } /* * Code adapted from Python 2.4.1 sources (Lib/calendar.py). */ time_t ldns_mktime_from_utc(const struct tm *tm) { int year = 1900 + tm->tm_year; time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year); time_t hours; time_t minutes; time_t seconds; int i; for (i = 0; i < tm->tm_mon; ++i) { days += mdays[i]; } if (tm->tm_mon > 1 && is_leap_year(year)) { ++days; } days += tm->tm_mday - 1; hours = days * 24 + tm->tm_hour; minutes = hours * 60 + tm->tm_min; seconds = minutes * 60 + tm->tm_sec; return seconds; } time_t mktime_from_utc(const struct tm *tm) { return ldns_mktime_from_utc(tm); } #if SIZEOF_TIME_T <= 4 static void ldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result) { int year = 1970; int new_year; while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) { new_year = year + (int) LDNS_DIV(days, 365); days -= (new_year - year) * 365; days -= leap_days(year, new_year); year = new_year; } result->tm_year = year; result->tm_yday = (int) days; } /* Number of days per month in a leap year. */ static const int leap_year_mdays[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static void ldns_mon_and_mday_from_year_and_yday(struct tm *result) { int idays = result->tm_yday; const int *mon_lengths = is_leap_year(result->tm_year) ? leap_year_mdays : mdays; result->tm_mon = 0; while (idays >= mon_lengths[result->tm_mon]) { idays -= mon_lengths[result->tm_mon++]; } result->tm_mday = idays + 1; } static void ldns_wday_from_year_and_yday(struct tm *result) { result->tm_wday = 4 /* 1-1-1970 was a thursday */ + LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7) + leap_days(1970, result->tm_year) + result->tm_yday; result->tm_wday = LDNS_MOD(result->tm_wday, 7); if (result->tm_wday < 0) { result->tm_wday += 7; } } static struct tm * ldns_gmtime64_r(int64_t clock, struct tm *result) { result->tm_isdst = 0; result->tm_sec = (int) LDNS_MOD(clock, 60); clock = LDNS_DIV(clock, 60); result->tm_min = (int) LDNS_MOD(clock, 60); clock = LDNS_DIV(clock, 60); result->tm_hour = (int) LDNS_MOD(clock, 24); clock = LDNS_DIV(clock, 24); ldns_year_and_yday_from_days_since_epoch(clock, result); ldns_mon_and_mday_from_year_and_yday(result); ldns_wday_from_year_and_yday(result); result->tm_year -= 1900; return result; } #endif /* SIZEOF_TIME_T <= 4 */ static int64_t ldns_serial_arithmitics_time(int32_t time, time_t now) { int32_t offset = time - (int32_t) now; return (int64_t) now + offset; } struct tm * ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result) { #if SIZEOF_TIME_T <= 4 int64_t secs_since_epoch = ldns_serial_arithmitics_time(time, now); return ldns_gmtime64_r(secs_since_epoch, result); #else time_t secs_since_epoch = ldns_serial_arithmitics_time(time, now); return gmtime_r(&secs_since_epoch, result); #endif } /** * Init the random source * applications should call this if they need entropy data within ldns * If openSSL is available, it is automatically seeded from /dev/urandom * or /dev/random * * If you need more entropy, or have no openssl available, this function * MUST be called at the start of the program * * If openssl *is* available, this function just adds more entropy **/ int ldns_init_random(FILE *fd, unsigned int size) { /* if fp is given, seed srandom with data from file otherwise use /dev/urandom */ FILE *rand_f; uint8_t *seed; size_t read = 0; unsigned int seed_i; struct timeval tv; /* we'll need at least sizeof(unsigned int) bytes for the standard prng seed */ if (size < (unsigned int) sizeof(seed_i)){ size = (unsigned int) sizeof(seed_i); } seed = LDNS_XMALLOC(uint8_t, size); if(!seed) { return 1; } if (!fd) { if ((rand_f = fopen("/dev/urandom", "r")) == NULL) { /* no readable /dev/urandom, try /dev/random */ if ((rand_f = fopen("/dev/random", "r")) == NULL) { /* no readable /dev/random either, and no entropy source given. we'll have to improvise */ for (read = 0; read < size; read++) { gettimeofday(&tv, NULL); seed[read] = (uint8_t) (tv.tv_usec % 256); } } else { read = fread(seed, 1, size, rand_f); } } else { read = fread(seed, 1, size, rand_f); } } else { rand_f = fd; read = fread(seed, 1, size, rand_f); } if (read < size) { LDNS_FREE(seed); if (!fd) fclose(rand_f); return 1; } else { #ifdef HAVE_SSL /* Seed the OpenSSL prng (most systems have it seeded automatically, in that case this call just adds entropy */ RAND_seed(seed, (int) size); #else /* Seed the standard prng, only uses the first * unsigned sizeof(unsiged int) bytes found in the entropy pool */ memcpy(&seed_i, seed, sizeof(seed_i)); srandom(seed_i); #endif LDNS_FREE(seed); } if (!fd) { if (rand_f) fclose(rand_f); } return 0; } /** * Get random number. * */ uint16_t ldns_get_random(void) { uint16_t rid = 0; #ifdef HAVE_SSL if (RAND_bytes((unsigned char*)&rid, 2) != 1) { rid = (uint16_t) random(); } #else rid = (uint16_t) random(); #endif return rid; } /* * BubbleBabble code taken from OpenSSH * Copyright (c) 2001 Carsten Raskgaard. All rights reserved. */ char * ldns_bubblebabble(uint8_t *data, size_t len) { char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; size_t i, j = 0, rounds, seed = 1; char *retval; rounds = (len / 2) + 1; retval = LDNS_XMALLOC(char, rounds * 6); if(!retval) return NULL; retval[j++] = 'x'; for (i = 0; i < rounds; i++) { size_t idx0, idx1, idx2, idx3, idx4; if ((i + 1 < rounds) || (len % 2 != 0)) { idx0 = (((((size_t)(data[2 * i])) >> 6) & 3) + seed) % 6; idx1 = (((size_t)(data[2 * i])) >> 2) & 15; idx2 = ((((size_t)(data[2 * i])) & 3) + (seed / 6)) % 6; retval[j++] = vowels[idx0]; retval[j++] = consonants[idx1]; retval[j++] = vowels[idx2]; if ((i + 1) < rounds) { idx3 = (((size_t)(data[(2 * i) + 1])) >> 4) & 15; idx4 = (((size_t)(data[(2 * i) + 1]))) & 15; retval[j++] = consonants[idx3]; retval[j++] = '-'; retval[j++] = consonants[idx4]; seed = ((seed * 5) + ((((size_t)(data[2 * i])) * 7) + ((size_t)(data[(2 * i) + 1])))) % 36; } } else { idx0 = seed % 6; idx1 = 16; idx2 = seed / 6; retval[j++] = vowels[idx0]; retval[j++] = consonants[idx1]; retval[j++] = vowels[idx2]; } } retval[j++] = 'x'; retval[j++] = '\0'; return retval; } /* * For backwards compatibility, because we have always exported this symbol. */ #ifdef HAVE_B64_NTOP int ldns_b64_ntop(const uint8_t* src, size_t srclength, char *target, size_t targsize); { return b64_ntop(src, srclength, target, targsize); } #endif /* * For backwards compatibility, because we have always exported this symbol. */ #ifdef HAVE_B64_PTON int ldns_b64_pton(const char* src, uint8_t *target, size_t targsize) { return b64_pton(src, target, targsize); } #endif static int ldns_b32_ntop_base(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz, bool extended_hex, bool add_padding) { size_t ret_sz; const char* b32 = extended_hex ? "0123456789abcdefghijklmnopqrstuv" : "abcdefghijklmnopqrstuvwxyz234567"; size_t c = 0; /* c is used to carry partial base32 character over * byte boundaries for sizes with a remainder. * (i.e. src_sz % 5 != 0) */ ret_sz = add_padding ? ldns_b32_ntop_calculate_size(src_sz) : ldns_b32_ntop_calculate_size_no_padding(src_sz); /* Do we have enough space? */ if (dst_sz < ret_sz + 1) return -1; /* We know the size; terminate the string */ dst[ret_sz] = '\0'; /* First process all chunks of five */ while (src_sz >= 5) { /* 00000... ........ ........ ........ ........ */ dst[0] = b32[(src[0] ) >> 3]; /* .....111 11...... ........ ........ ........ */ dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6]; /* ........ ..22222. ........ ........ ........ */ dst[2] = b32[(src[1] & 0x3e) >> 1]; /* ........ .......3 3333.... ........ ........ */ dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4]; /* ........ ........ ....4444 4....... ........ */ dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7]; /* ........ ........ ........ .55555.. ........ */ dst[5] = b32[(src[3] & 0x7c) >> 2]; /* ........ ........ ........ ......66 666..... */ dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5]; /* ........ ........ ........ ........ ...77777 */ dst[7] = b32[(src[4] & 0x1f) ]; src_sz -= 5; src += 5; dst += 8; } /* Process what remains */ switch (src_sz) { case 4: /* ........ ........ ........ ......66 666..... */ dst[6] = b32[(src[3] & 0x03) << 3]; /* ........ ........ ........ .55555.. ........ */ dst[5] = b32[(src[3] & 0x7c) >> 2]; /* ........ ........ ....4444 4....... ........ */ c = src[3] >> 7 ; case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c]; /* ........ .......3 3333.... ........ ........ */ c = src[2] >> 4 ; case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c]; /* ........ ..22222. ........ ........ ........ */ dst[2] = b32[(src[1] & 0x3e) >> 1]; /* .....111 11...... ........ ........ ........ */ c = src[1] >> 6 ; case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c]; /* 00000... ........ ........ ........ ........ */ dst[0] = b32[ src[0] >> 3]; } /* Add padding */ if (add_padding) { switch (src_sz) { case 1: dst[2] = '='; dst[3] = '='; case 2: dst[4] = '='; case 3: dst[5] = '='; dst[6] = '='; case 4: dst[7] = '='; } } return (int)ret_sz; } int ldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) { return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true); } int ldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) { return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true); } #ifndef HAVE_B32_NTOP int b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) { return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true); } int b32_ntop_extended_hex(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) { return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true); } #endif /* ! HAVE_B32_NTOP */ static int ldns_b32_pton_base(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz, bool extended_hex, bool check_padding) { size_t i = 0; char ch = '\0'; uint8_t buf[8]; uint8_t* start = dst; while (src_sz) { /* Collect 8 characters in buf (if possible) */ for (i = 0; i < 8; i++) { do { ch = *src++; --src_sz; } while (isspace(ch) && src_sz > 0); if (ch == '=' || ch == '\0') break; else if (extended_hex) if (ch >= '0' && ch <= '9') buf[i] = (uint8_t)ch - '0'; else if (ch >= 'a' && ch <= 'v') buf[i] = (uint8_t)ch - 'a' + 10; else if (ch >= 'A' && ch <= 'V') buf[i] = (uint8_t)ch - 'A' + 10; else return -1; else if (ch >= 'a' && ch <= 'z') buf[i] = (uint8_t)ch - 'a'; else if (ch >= 'A' && ch <= 'Z') buf[i] = (uint8_t)ch - 'A'; else if (ch >= '2' && ch <= '7') buf[i] = (uint8_t)ch - '2' + 26; else return -1; } /* Less that 8 characters. We're done. */ if (i < 8) break; /* Enough space available at the destination? */ if (dst_sz < 5) return -1; /* 00000... ........ ........ ........ ........ */ /* .....111 11...... ........ ........ ........ */ dst[0] = buf[0] << 3 | buf[1] >> 2; /* .....111 11...... ........ ........ ........ */ /* ........ ..22222. ........ ........ ........ */ /* ........ .......3 3333.... ........ ........ */ dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; /* ........ .......3 3333.... ........ ........ */ /* ........ ........ ....4444 4....... ........ */ dst[2] = buf[3] << 4 | buf[4] >> 1; /* ........ ........ ....4444 4....... ........ */ /* ........ ........ ........ .55555.. ........ */ /* ........ ........ ........ ......66 666..... */ dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; /* ........ ........ ........ ......66 666..... */ /* ........ ........ ........ ........ ...77777 */ dst[4] = buf[6] << 5 | buf[7]; dst += 5; dst_sz -= 5; } /* Not ending on a eight byte boundary? */ if (i > 0 && i < 8) { /* Enough space available at the destination? */ if (dst_sz < (i + 1) / 2) return -1; switch (i) { case 7: /* ........ ........ ........ ......66 666..... */ /* ........ ........ ........ .55555.. ........ */ /* ........ ........ ....4444 4....... ........ */ dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; case 5: /* ........ ........ ....4444 4....... ........ */ /* ........ .......3 3333.... ........ ........ */ dst[2] = buf[3] << 4 | buf[4] >> 1; case 4: /* ........ .......3 3333.... ........ ........ */ /* ........ ..22222. ........ ........ ........ */ /* .....111 11...... ........ ........ ........ */ dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; case 2: /* .....111 11...... ........ ........ ........ */ /* 00000... ........ ........ ........ ........ */ dst[0] = buf[0] << 3 | buf[1] >> 2; break; default: return -1; } dst += (i + 1) / 2; if (check_padding) { /* Check remaining padding characters */ if (ch != '=') return -1; /* One down, 8 - i - 1 more to come... */ for (i = 8 - i - 1; i > 0; i--) { do { if (src_sz == 0) return -1; ch = *src++; src_sz--; } while (isspace(ch)); if (ch != '=') return -1; } } } return dst - start; } int ldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) { return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true); } int ldns_b32_pton_extended_hex(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) { return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true); } #ifndef HAVE_B32_PTON int b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) { return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true); } int b32_pton_extended_hex(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) { return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true); } #endif /* ! HAVE_B32_PTON */ Net-LDNS-0.75/src/ldns/wire2host.c000644 000770 000024 00000031325 12471046240 017141 0ustar00calledstaff000000 000000 /* * wire2host.c * * conversion routines from the wire to the host * format. * This will usually just a re-ordering of the * data (as we store it in network format) * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #include #include /*#include */ #include #include /* * Set of macro's to deal with the dns message header as specified * in RFC1035 in portable way. * */ /* * * 1 1 1 1 1 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | ID | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | QDCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | ANCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | NSCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | ARCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * */ /* allocates memory to *dname! */ ldns_status ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos) { uint8_t label_size; uint16_t pointer_target; uint8_t pointer_target_buf[2]; size_t dname_pos = 0; size_t uncompressed_length = 0; size_t compression_pos = 0; uint8_t tmp_dname[LDNS_MAX_DOMAINLEN]; unsigned int pointer_count = 0; if (pos == NULL) { return LDNS_STATUS_WIRE_RDATA_ERR; } if (*pos >= max) { return LDNS_STATUS_PACKET_OVERFLOW; } label_size = wire[*pos]; while (label_size > 0) { /* compression */ while (label_size >= 192) { if (compression_pos == 0) { compression_pos = *pos + 2; } pointer_count++; /* remove first two bits */ if (*pos + 2 > max) { return LDNS_STATUS_PACKET_OVERFLOW; } pointer_target_buf[0] = wire[*pos] & 63; pointer_target_buf[1] = wire[*pos + 1]; pointer_target = ldns_read_uint16(pointer_target_buf); if (pointer_target == 0) { return LDNS_STATUS_INVALID_POINTER; } else if (pointer_target >= max) { return LDNS_STATUS_INVALID_POINTER; } else if (pointer_count > LDNS_MAX_POINTERS) { return LDNS_STATUS_INVALID_POINTER; } *pos = pointer_target; label_size = wire[*pos]; } if(label_size == 0) break; /* break from pointer to 0 byte */ if (label_size > LDNS_MAX_LABELLEN) { return LDNS_STATUS_LABEL_OVERFLOW; } if (*pos + 1 + label_size > max) { return LDNS_STATUS_LABEL_OVERFLOW; } /* check space for labelcount itself */ if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) { return LDNS_STATUS_DOMAINNAME_OVERFLOW; } tmp_dname[dname_pos] = label_size; if (label_size > 0) { dname_pos++; } *pos = *pos + 1; if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) { return LDNS_STATUS_DOMAINNAME_OVERFLOW; } memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size); uncompressed_length += label_size + 1; dname_pos += label_size; *pos = *pos + label_size; if (*pos < max) { label_size = wire[*pos]; } } if (compression_pos > 0) { *pos = compression_pos; } else { *pos = *pos + 1; } if (dname_pos >= LDNS_MAX_DOMAINLEN) { return LDNS_STATUS_DOMAINNAME_OVERFLOW; } tmp_dname[dname_pos] = 0; dname_pos++; *dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, (uint16_t) dname_pos, tmp_dname); if (!*dname) { return LDNS_STATUS_MEM_ERR; } return LDNS_STATUS_OK; } /* maybe make this a goto error so data can be freed or something/ */ #define LDNS_STATUS_CHECK_RETURN(st) {if (st != LDNS_STATUS_OK) { return st; }} #define LDNS_STATUS_CHECK_GOTO(st, label) {if (st != LDNS_STATUS_OK) { /*printf("STG %s:%d: status code %d\n", __FILE__, __LINE__, st);*/ goto label; }} ldns_status ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) { size_t end; size_t cur_rdf_length; uint8_t rdf_index; uint8_t *data; uint16_t rd_length; ldns_rdf *cur_rdf = NULL; ldns_rdf_type cur_rdf_type; const ldns_rr_descriptor *descriptor; ldns_status status; assert(rr != NULL); descriptor = ldns_rr_descript(ldns_rr_get_type(rr)); if (*pos + 2 > max) { return LDNS_STATUS_PACKET_OVERFLOW; } rd_length = ldns_read_uint16(&wire[*pos]); *pos = *pos + 2; if (*pos + rd_length > max) { return LDNS_STATUS_PACKET_OVERFLOW; } end = *pos + (size_t) rd_length; rdf_index = 0; while (*pos < end && rdf_index < ldns_rr_descriptor_maximum(descriptor)) { cur_rdf_length = 0; cur_rdf_type = ldns_rr_descriptor_field_type( descriptor, rdf_index); /* handle special cases immediately, set length for fixed length rdata and do them below */ switch (cur_rdf_type) { case LDNS_RDF_TYPE_DNAME: status = ldns_wire2dname(&cur_rdf, wire, max, pos); LDNS_STATUS_CHECK_RETURN(status); break; case LDNS_RDF_TYPE_CLASS: case LDNS_RDF_TYPE_ALG: case LDNS_RDF_TYPE_CERTIFICATE_USAGE: case LDNS_RDF_TYPE_SELECTOR: case LDNS_RDF_TYPE_MATCHING_TYPE: case LDNS_RDF_TYPE_INT8: cur_rdf_length = LDNS_RDF_SIZE_BYTE; break; case LDNS_RDF_TYPE_TYPE: case LDNS_RDF_TYPE_INT16: case LDNS_RDF_TYPE_CERT_ALG: cur_rdf_length = LDNS_RDF_SIZE_WORD; break; case LDNS_RDF_TYPE_TIME: case LDNS_RDF_TYPE_INT32: case LDNS_RDF_TYPE_A: case LDNS_RDF_TYPE_PERIOD: cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD; break; case LDNS_RDF_TYPE_TSIGTIME: case LDNS_RDF_TYPE_EUI48: cur_rdf_length = LDNS_RDF_SIZE_6BYTES; break; case LDNS_RDF_TYPE_ILNP64: case LDNS_RDF_TYPE_EUI64: cur_rdf_length = LDNS_RDF_SIZE_8BYTES; break; case LDNS_RDF_TYPE_AAAA: cur_rdf_length = LDNS_RDF_SIZE_16BYTES; break; case LDNS_RDF_TYPE_STR: case LDNS_RDF_TYPE_NSEC3_SALT: case LDNS_RDF_TYPE_TAG: /* len is stored in first byte * it should be in the rdf too, so just * copy len+1 from this position */ cur_rdf_length = ((size_t) wire[*pos]) + 1; break; case LDNS_RDF_TYPE_INT16_DATA: if (*pos + 2 > end) { return LDNS_STATUS_PACKET_OVERFLOW; } cur_rdf_length = (size_t) ldns_read_uint16(&wire[*pos]) + 2; break; case LDNS_RDF_TYPE_HIP: if (*pos + 4 > end) { return LDNS_STATUS_PACKET_OVERFLOW; } cur_rdf_length = (size_t) wire[*pos] + (size_t) ldns_read_uint16(&wire[*pos + 2]) + 4; break; case LDNS_RDF_TYPE_B32_EXT: case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: /* length is stored in first byte */ cur_rdf_length = ((size_t) wire[*pos]) + 1; break; case LDNS_RDF_TYPE_APL: case LDNS_RDF_TYPE_B64: case LDNS_RDF_TYPE_HEX: case LDNS_RDF_TYPE_NSEC: case LDNS_RDF_TYPE_UNKNOWN: case LDNS_RDF_TYPE_SERVICE: case LDNS_RDF_TYPE_LOC: case LDNS_RDF_TYPE_WKS: case LDNS_RDF_TYPE_NSAP: case LDNS_RDF_TYPE_ATMA: case LDNS_RDF_TYPE_IPSECKEY: case LDNS_RDF_TYPE_LONG_STR: case LDNS_RDF_TYPE_NONE: /* * Read to end of rr rdata */ cur_rdf_length = end - *pos; break; } /* fixed length rdata */ if (cur_rdf_length > 0) { if (cur_rdf_length + *pos > end) { return LDNS_STATUS_PACKET_OVERFLOW; } data = LDNS_XMALLOC(uint8_t, rd_length); if (!data) { return LDNS_STATUS_MEM_ERR; } memcpy(data, &wire[*pos], cur_rdf_length); cur_rdf = ldns_rdf_new(cur_rdf_type, cur_rdf_length, data); *pos = *pos + cur_rdf_length; } if (cur_rdf) { ldns_rr_push_rdf(rr, cur_rdf); cur_rdf = NULL; } rdf_index++; } /* while (rdf_index < ldns_rr_descriptor_maximum(descriptor)) */ return LDNS_STATUS_OK; } /* TODO: can *pos be incremented at READ_INT? or maybe use something like RR_CLASS(wire)? uhhm Jelte?? */ ldns_status ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max, size_t *pos, ldns_pkt_section section) { ldns_rdf *owner = NULL; ldns_rr *rr = ldns_rr_new(); ldns_status status; status = ldns_wire2dname(&owner, wire, max, pos); LDNS_STATUS_CHECK_GOTO(status, status_error); ldns_rr_set_owner(rr, owner); if (*pos + 4 > max) { status = LDNS_STATUS_PACKET_OVERFLOW; goto status_error; } ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos])); *pos = *pos + 2; ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos])); *pos = *pos + 2; if (section != LDNS_SECTION_QUESTION) { if (*pos + 4 > max) { status = LDNS_STATUS_PACKET_OVERFLOW; goto status_error; } ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos])); *pos = *pos + 4; status = ldns_wire2rdf(rr, wire, max, pos); LDNS_STATUS_CHECK_GOTO(status, status_error); ldns_rr_set_question(rr, false); } else { ldns_rr_set_question(rr, true); } *rr_p = rr; return LDNS_STATUS_OK; status_error: ldns_rr_free(rr); return status; } static ldns_status ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos) { if (*pos + LDNS_HEADER_SIZE > max) { return LDNS_STATUS_WIRE_INCOMPLETE_HEADER; } else { ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire)); ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire)); ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire)); ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire)); ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire)); ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire)); ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire)); ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire)); ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire)); ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire)); ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire)); ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire)); ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire)); ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire)); *pos += LDNS_HEADER_SIZE; return LDNS_STATUS_OK; } } ldns_status ldns_buffer2pkt_wire(ldns_pkt **packet, ldns_buffer *buffer) { /* lazy */ return ldns_wire2pkt(packet, ldns_buffer_begin(buffer), ldns_buffer_limit(buffer)); } ldns_status ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max) { size_t pos = 0; uint16_t i; ldns_rr *rr; ldns_pkt *packet = ldns_pkt_new(); ldns_status status = LDNS_STATUS_OK; uint8_t have_edns = 0; uint8_t data[4]; status = ldns_wire2pkt_hdr(packet, wire, max, &pos); LDNS_STATUS_CHECK_GOTO(status, status_error); for (i = 0; i < ldns_pkt_qdcount(packet); i++) { status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION); if (status == LDNS_STATUS_PACKET_OVERFLOW) { status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION; } LDNS_STATUS_CHECK_GOTO(status, status_error); if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) { ldns_pkt_free(packet); return LDNS_STATUS_INTERNAL_ERR; } } for (i = 0; i < ldns_pkt_ancount(packet); i++) { status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER); if (status == LDNS_STATUS_PACKET_OVERFLOW) { status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER; } LDNS_STATUS_CHECK_GOTO(status, status_error); if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) { ldns_pkt_free(packet); return LDNS_STATUS_INTERNAL_ERR; } } for (i = 0; i < ldns_pkt_nscount(packet); i++) { status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY); if (status == LDNS_STATUS_PACKET_OVERFLOW) { status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY; } LDNS_STATUS_CHECK_GOTO(status, status_error); if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) { ldns_pkt_free(packet); return LDNS_STATUS_INTERNAL_ERR; } } for (i = 0; i < ldns_pkt_arcount(packet); i++) { status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL); if (status == LDNS_STATUS_PACKET_OVERFLOW) { status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL; } LDNS_STATUS_CHECK_GOTO(status, status_error); if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) { ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr)); ldns_write_uint32(data, ldns_rr_ttl(rr)); ldns_pkt_set_edns_extended_rcode(packet, data[0]); ldns_pkt_set_edns_version(packet, data[1]); ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2])); /* edns might not have rdfs */ if (ldns_rr_rdf(rr, 0)) { ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0))); } ldns_rr_free(rr); have_edns += 1; } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) { ldns_pkt_set_tsig(packet, rr); ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1); } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) { ldns_pkt_free(packet); return LDNS_STATUS_INTERNAL_ERR; } } ldns_pkt_set_size(packet, max); if(have_edns) ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - have_edns); packet->_edns_present = have_edns; *packet_p = packet; return status; status_error: ldns_pkt_free(packet); return status; } Net-LDNS-0.75/src/ldns/zone.c000644 000770 000024 00000014233 12471046240 016165 0ustar00calledstaff000000 000000 /* zone.c * * Functions for ldns_zone structure * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * See the file LICENSE for the license */ #include #include #include #include ldns_rr * ldns_zone_soa(const ldns_zone *z) { return z->_soa; } size_t ldns_zone_rr_count(const ldns_zone *z) { return ldns_rr_list_rr_count(z->_rrs); } void ldns_zone_set_soa(ldns_zone *z, ldns_rr *soa) { z->_soa = soa; } ldns_rr_list * ldns_zone_rrs(const ldns_zone *z) { return z->_rrs; } void ldns_zone_set_rrs(ldns_zone *z, ldns_rr_list *rrlist) { z->_rrs = rrlist; } bool ldns_zone_push_rr_list(ldns_zone *z, ldns_rr_list *list) { return ldns_rr_list_cat(ldns_zone_rrs(z), list); } bool ldns_zone_push_rr(ldns_zone *z, ldns_rr *rr) { return ldns_rr_list_push_rr( ldns_zone_rrs(z), rr); } /* * Get the list of glue records in a zone * XXX: there should be a way for this to return error, other than NULL, * since NULL is a valid return */ ldns_rr_list * ldns_zone_glue_rr_list(const ldns_zone *z) { /* when do we find glue? It means we find an IP address * (AAAA/A) for a nameserver listed in the zone * * Alg used here: * first find all the zonecuts (NS records) * find all the AAAA or A records (can be done it the * above loop). * * Check if the aaaa/a list are subdomains under the * NS domains. * If yes -> glue, if no -> not glue */ ldns_rr_list *zone_cuts; ldns_rr_list *addr; ldns_rr_list *glue; ldns_rr *r, *ns, *a; ldns_rdf *dname_a, *ns_owner; size_t i,j; zone_cuts = NULL; addr = NULL; glue = NULL; /* we cannot determine glue in a 'zone' without a SOA */ if (!ldns_zone_soa(z)) { return NULL; } zone_cuts = ldns_rr_list_new(); if (!zone_cuts) goto memory_error; addr = ldns_rr_list_new(); if (!addr) goto memory_error; glue = ldns_rr_list_new(); if (!glue) goto memory_error; for(i = 0; i < ldns_zone_rr_count(z); i++) { r = ldns_rr_list_rr(ldns_zone_rrs(z), i); if (ldns_rr_get_type(r) == LDNS_RR_TYPE_A || ldns_rr_get_type(r) == LDNS_RR_TYPE_AAAA) { /* possibly glue */ if (!ldns_rr_list_push_rr(addr, r)) goto memory_error; continue; } if (ldns_rr_get_type(r) == LDNS_RR_TYPE_NS) { /* multiple zones will end up here - * for now; not a problem */ /* don't add NS records for the current zone itself */ if (ldns_rdf_compare(ldns_rr_owner(r), ldns_rr_owner(ldns_zone_soa(z))) != 0) { if (!ldns_rr_list_push_rr(zone_cuts, r)) goto memory_error; } continue; } } /* will sorting make it quicker ?? */ for(i = 0; i < ldns_rr_list_rr_count(zone_cuts); i++) { ns = ldns_rr_list_rr(zone_cuts, i); ns_owner = ldns_rr_owner(ns); for(j = 0; j < ldns_rr_list_rr_count(addr); j++) { a = ldns_rr_list_rr(addr, j); dname_a = ldns_rr_owner(a); if (ldns_dname_is_subdomain(dname_a, ns_owner) || ldns_dname_compare(dname_a, ns_owner) == 0) { /* GLUE! */ if (!ldns_rr_list_push_rr(glue, a)) goto memory_error; } } } ldns_rr_list_free(addr); ldns_rr_list_free(zone_cuts); if (ldns_rr_list_rr_count(glue) == 0) { ldns_rr_list_free(glue); return NULL; } else { return glue; } memory_error: if (zone_cuts) { LDNS_FREE(zone_cuts); } if (addr) { ldns_rr_list_free(addr); } if (glue) { ldns_rr_list_free(glue); } return NULL; } ldns_zone * ldns_zone_new(void) { ldns_zone *z; z = LDNS_MALLOC(ldns_zone); if (!z) { return NULL; } z->_rrs = ldns_rr_list_new(); if (!z->_rrs) { LDNS_FREE(z); return NULL; } ldns_zone_set_soa(z, NULL); return z; } /* we regocnize: * $TTL, $ORIGIN */ ldns_status ldns_zone_new_frm_fp(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, ldns_rr_class c) { return ldns_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL); } /* XXX: class is never used */ ldns_status ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int *line_nr) { ldns_zone *newzone; ldns_rr *rr; uint32_t my_ttl; ldns_rdf *my_origin; ldns_rdf *my_prev; bool soa_seen = false; /* 2 soa are an error */ ldns_status s; ldns_status ret; /* most cases of error are memory problems */ ret = LDNS_STATUS_MEM_ERR; newzone = NULL; my_origin = NULL; my_prev = NULL; my_ttl = ttl; if (origin) { my_origin = ldns_rdf_clone(origin); if (!my_origin) goto error; /* also set the prev */ my_prev = ldns_rdf_clone(origin); if (!my_prev) goto error; } newzone = ldns_zone_new(); if (!newzone) goto error; while(!feof(fp)) { s = ldns_rr_new_frm_fp_l(&rr, fp, &my_ttl, &my_origin, &my_prev, line_nr); switch (s) { case LDNS_STATUS_OK: if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { if (soa_seen) { /* second SOA * just skip, maybe we want to say * something??? */ ldns_rr_free(rr); continue; } soa_seen = true; ldns_zone_set_soa(newzone, rr); /* set origin to soa if not specified */ if (!my_origin) { my_origin = ldns_rdf_clone(ldns_rr_owner(rr)); } continue; } /* a normal RR - as sofar the DNS is normal */ if (!ldns_zone_push_rr(newzone, rr)) goto error; case LDNS_STATUS_SYNTAX_EMPTY: /* empty line was seen */ case LDNS_STATUS_SYNTAX_TTL: /* the function set the ttl */ break; case LDNS_STATUS_SYNTAX_ORIGIN: /* the function set the origin */ break; case LDNS_STATUS_SYNTAX_INCLUDE: ret = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL; break; default: ret = s; goto error; } } if (my_origin) { ldns_rdf_deep_free(my_origin); } if (my_prev) { ldns_rdf_deep_free(my_prev); } if (z) { *z = newzone; } else { ldns_zone_free(newzone); } return LDNS_STATUS_OK; error: if (my_origin) { ldns_rdf_deep_free(my_origin); } if (my_prev) { ldns_rdf_deep_free(my_prev); } if (newzone) { ldns_zone_free(newzone); } return ret; } void ldns_zone_sort(ldns_zone *zone) { ldns_rr_list *zrr; assert(zone != NULL); zrr = ldns_zone_rrs(zone); ldns_rr_list_sort(zrr); } void ldns_zone_free(ldns_zone *zone) { ldns_rr_list_free(zone->_rrs); LDNS_FREE(zone); } void ldns_zone_deep_free(ldns_zone *zone) { ldns_rr_free(zone->_soa); ldns_rr_list_deep_free(zone->_rrs); LDNS_FREE(zone); } Net-LDNS-0.75/src/ldns/compat/b64_ntop.c000644 000770 000024 00000016376 12504030124 020131 0ustar00calledstaff000000 000000 /* * Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #include #include static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the ------------------------------------------------- following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ int ldns_b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; uint8_t input[3]; uint8_t output[4]; size_t i; if (srclength == 0) { if (targsize > 0) { target[0] = '\0'; return 0; } else { return -1; } } while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; assert(output[0] < 64); assert(output[1] < 64); assert(output[2] < 64); assert(output[3] < 64); if (datalength + 4 > targsize) { return (-1); } target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = (uint8_t) '\0'; for (i = 0; i < srclength; i++) input[i] = *src++; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); assert(output[0] < 64); assert(output[1] < 64); assert(output[2] < 64); if (datalength + 4 > targsize) { return (-2); } target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) { target[datalength++] = Pad64; } else { target[datalength++] = Base64[output[2]]; } target[datalength++] = Pad64; } if (datalength >= targsize) { return (-3); } target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (int) (datalength); } Net-LDNS-0.75/src/ldns/compat/b64_pton.c000644 000770 000024 00000020745 12504030124 020124 0ustar00calledstaff000000 000000 /* * Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #include #include static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the ------------------------------------------------- following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ int ldns_b64_pton(char const *origsrc, uint8_t *target, size_t targsize) { unsigned char const* src = (unsigned char*)origsrc; int tarindex, state, ch; char *pos; state = 0; tarindex = 0; if (strlen(origsrc) == 0) { return 0; } while ((ch = *src++) != '\0') { if (isspace((unsigned char)ch)) /* Skip whitespace anywhere. */ continue; if (ch == Pad64) break; pos = strchr(Base64, ch); if (pos == 0) { /* A non-base64 character. */ return (-1); } switch (state) { case 0: if (target) { if ((size_t)tarindex >= targsize) return (-1); target[tarindex] = (pos - Base64) << 2; } state = 1; break; case 1: if (target) { if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= (pos - Base64) >> 4; target[tarindex+1] = ((pos - Base64) & 0x0f) << 4 ; } tarindex++; state = 2; break; case 2: if (target) { if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= (pos - Base64) >> 2; target[tarindex+1] = ((pos - Base64) & 0x03) << 6; } tarindex++; state = 3; break; case 3: if (target) { if ((size_t)tarindex >= targsize) return (-1); target[tarindex] |= (pos - Base64); } tarindex++; state = 0; break; default: abort(); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void)NULL; ch != '\0'; ch = *src++) if (!isspace((unsigned char)ch)) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void)NULL; ch != '\0'; ch = *src++) if (!isspace((unsigned char)ch)) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target && target[tarindex] != 0) return (-1); } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } Net-LDNS-0.75/src/ldns/compat/strlcpy.c000644 000770 000024 00000003212 12471046240 020170 0ustar00calledstaff000000 000000 /* from openssh 4.3p2 compat/strlcpy.c */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ #include #ifndef HAVE_STRLCPY #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } #endif /* !HAVE_STRLCPY */ Net-LDNS-0.75/lib/Net/000755 000770 000024 00000000000 12510741546 014615 5ustar00calledstaff000000 000000 Net-LDNS-0.75/lib/Net/LDNS/000755 000770 000024 00000000000 12510741546 015355 5ustar00calledstaff000000 000000 Net-LDNS-0.75/lib/Net/LDNS.pm000644 000770 000024 00000012641 12506265030 015711 0ustar00calledstaff000000 000000 package Net::LDNS; use 5.10.1; our $VERSION = '0.75'; use parent 'Exporter'; our @EXPORT_OK = qw[to_idn has_idn ldns_version load_zonefile]; our %EXPORT_TAGS = ( all => \@EXPORT_OK ); require XSLoader; XSLoader::load( __PACKAGE__, $VERSION ); use Net::LDNS::RR; use Net::LDNS::Packet; 1; =head1 NAME Net::LDNS - DNS-talking module based on the ldns C library =head1 SYNOPSIS my $resolver = Net::LDNS->new('8.8.8.8'); my $packet = $resolver->query('www.iis.se'); say $packet->string; =head1 DESCRIPTION C represents a resolver, which is the part of the system responsible for sending queries and receiving answers to them. =head1 EXPORTABLE FUNCTIONS =over =item lib_version() Returns the ldns version string. Can be exported, but is not by default. =item to_idn($name, ...) Takes a number of strings and returns a list of them converted to IDNA format. Assumes that the strings have been converted to Perl's internal encoding before it's called. Can be exported, but is not by default. This function requires that GNU libidn was present when L was compiled. If not, calling C will result in an exception getting thrown. =item has_idn() Takes no arguments. Returns true if libidn was present at compilation, false if not. =item has_gost() Takes no arguments. Returns true if GOST support was present at compilation, false if not. =item load_zonefile($filename) Load all resource records in a zone file, returning them as a list. =back =head1 CLASS METHOD =over =item new($addr,...) Creates a new resolver object. If given no arguments, if will pick up nameserver addresses from the system configuration (F or equivalent). If given a single argument that is C, it will not know of any nameservers and all attempts to send queries will throw exceptions. If given one or more arguments that are not C, attempts to parse them as IPv4 and IPv6 addresses will be made, and if successful make up a list of servers to send queries to. If an argument cannot be parsed as an IP address, an exception will be thrown. =back =head1 INSTANCE METHODS =over =item query($name, $type, $class) Send a query for the given triple. If type or class are not provided they default to A and IN, respectively. Returns a L or undef. =item name2addr($name) Asks this resolver to look up A and AAAA records for the given name, and return a list of the IP addresses (as strings). In scalar context, returns the number of addresses found. =item addr2name($addr) Takes an IP address, asks the resolver to do PTR lookups and returns the names found. In scalar context, returns the number of names found. =item recurse($flag) Returns the setting of the recursion flag. If given an argument, it will be treated as a boolean and the flag set accordingly. =item debug($flag) Gets and optionally sets the debug flag. =item dnssec($flag) Get and optionally sets the DNSSEC flag. =item cd($flag) Get and optionally sets the CD flag. =item igntc($flag) Get and optionally sets the igntc flag. =item usevc($flag) Get and optionally sets the usevc flag. =item retry($count) Get and optionally set the number of retries. =item retrans($seconds) Get and optionally set the number of seconds between retries. =item port($port) Get and optionally set the destination port for requests. =item edns_size($size) Get and optionally set the EDNS0 UDP maximum size. =item axfr( $domain, $callback, $class ) Perform an AXFR operation. C<$callback> must be a code reference, which will be called once for every received resource record with the RR object as its one and only argument. After every such call, the return value of the callback will be examined, and if the value is false the AXFR process will be aborted. The return value of the C method itself will be true if the transfer completed normally, and false if it was aborted because the callback returned a false value. If anything goes wrong during the process, an exception will be thrown. As an example, saving all the RRs received from an AXFR can be done like this: my @rrs; $resolver->axfr( $domain, sub { my ($rr) = @_; push @rrs, $rr; return 1;} ); =item axfr_start($domain,$class) Deprecated. Use L instead. Set this resolver object up for a zone transfer of the specified domain. If C<$class> is not given, it defaults to IN. =item axfr_next() Deprecated. Use L instead. Get the next RR in the zone transfer. L must have been done before this is called, and after this is called L should be used to check if there are more records to get. If there's any problem, an exception will be thrown. Basically, the sequence should be something like: $res->axfr_start('example.org'); do { push @rrlist, $res->axfr_next; } until $res->axfr_complete; =item axfr_complete() Deprecated. Use L instead. Returns false if there is a started zone transfer with more records to get, and true if the started transfer has completed. =item axfr_last_packet() Deprecated. Use L instead. If L threw an exception, this method returns the L that made it do so. The packet's RCODE is likely to say what the problem was (for example, NOTAUTH or NXDOMAIN). =item timeout($time) Get and/or set the socket timeout for the resolver. =item source($addr) Get and/or set the IP address the resolver should try to send its queries from. =back Net-LDNS-0.75/lib/Net/LDNS/Packet.pm000644 000770 000024 00000010632 12506212323 017113 0ustar00calledstaff000000 000000 package Net::LDNS::Packet; use 5.10.1; use Net::LDNS; use MIME::Base64; sub TO_JSON { my ( $self ) = @_; return { 'Net::LDNS::Packet' => { data => encode_base64( $self->wireformat, '' ), answerfrom => $self->answerfrom, timestamp => $self->timestamp, querytime => $self->querytime, } }; } sub data { my ( $self ) = @_; return $self->wireformat; } 1; =head1 NAME Net::LDNS::Packet - objects representing DNS packets =head1 SYNOPSIS my $p = $resolver->query('www.iis.se'); foreach my $rr ($p->answer) { say $rr->string if $rr->type eq 'A'; } =head1 CLASS METHODS =over =item new($name, $type, $class) Create a new packet, holding nothing by a query record for the provided triplet. C<$type> and C<$class> are optional, and default to A and IN respectively. =item new_from_wireformat($data) Creates a new L object from the given wireformat data, if possible. Throws an exception if not. =back =head1 INSTANCE METHODS =over =item rcode([$string]) Returns the packet RCODE. If given an argument, tries to set the RCODE to the relevant value. If the given string isn't recognized as an RCODE, an exception will be thrown. =item opcode([$string]) Returns the packet OPCODE. If given an argument, tries to set the OPCODE to the relevant value. If the given string isn't recognized as an OPCODE, an exception will be thrown. =item id([$value]) Returns the packet id number. If given an argument, sets the ID value to that value. =item qr() =item aa() =item tc() =item rd() =item cd() =item ra() =item ad() =item do() Reads and/or sets the equivalently named flags. =item size() Returns the length of the packet's wireformat form in octets. =item edns_size() Gets and/or sets the EDNS0 UDP size. =item edns_rcode() Gets and/or sets the EDNS0 Extended RCODE field. =item needs_edns() This method returns true if the packet has the DO flag set, an EDNS0 size set, and EDNS0 extended RCODE set or if the OPT pseudo-RR has one or more RDATA fields. It can fail to correctly flag a packet with an OPT pseudo-RR as having EDNS, if the pseudo-RR specifies an UDP size of zero, an extended RCODE of zero and the DO flag is unset. Since any UDP size less than 512 must be interpreted as 512, packets like that should be very rare in practice if they exist at all. Note that the OPT pseudo-RR is not visible as an RR in the packet, nor is it included in the RR count header fields. =item has_edns() An alias for needs_edns(). =item edns_version($version) Get or set the EDNS version in the packet. For incoming packets, returns 0 if the packet does not have an OPT pseudo-RR and 0 if it's an EDNS0 packet. It's thus rather pointless until such time as EDNS1 is defined. =item querytime([$value]) Returns the time the query this packet is the answer to took to execute, in milliseconds. If given a value, sets the querytime to that value. =item answerfrom($ipaddr) Returns and optionally sets the IP address the packet was received from. If an attempt is made to set it to a string that cannot be parsed as an IPv4 or IPv6 address, an exception is thrown. =item timestamp($time) The time when the query was sent or received (the ldns docs don't specify), as a floating-point value on the Unix time_t scale (that is, the same kind of value used by L). Conversion effects between floating-point and C means that the precision of the value is probably not reliable at the microsecond level, even if you computer's clock happen to be. =item question() =item answer() =item authority() =item additional() Returns list of objects representing the RRs in the named section. They will be of classes appropriate to their types, but all will have C as a base class. =item unique_push($section, $rr) Push an RR object into the given section, if an identical RR isn't already present. If the section isn't one of "question", "answer", "authority" or "additional" an exception will be thrown. C<$rr> must be a L subclass. =item string() Returns a string with the packet and its contents in common presentation format. =item wireformat() Returns a Perl string holding the packet in wire format. =item type() Returns the ldns library's guess as to the content of the packet. One of the strings C, C, C, C, C or C. =back Net-LDNS-0.75/lib/Net/LDNS/RR/000755 000770 000024 00000000000 12510741546 015700 5ustar00calledstaff000000 000000 Net-LDNS-0.75/lib/Net/LDNS/RR.pm000644 000770 000024 00000007210 12470405037 016233 0ustar00calledstaff000000 000000 package Net::LDNS::RR; use Net::LDNS::RR::A; use Net::LDNS::RR::A6; use Net::LDNS::RR::AAAA; use Net::LDNS::RR::AFSDB; use Net::LDNS::RR::APL; use Net::LDNS::RR::ATMA; use Net::LDNS::RR::CAA; use Net::LDNS::RR::CDS; use Net::LDNS::RR::CERT; use Net::LDNS::RR::CNAME; use Net::LDNS::RR::DHCID; use Net::LDNS::RR::DLV; use Net::LDNS::RR::DNAME; use Net::LDNS::RR::DNSKEY; use Net::LDNS::RR::DS; use Net::LDNS::RR::EID; use Net::LDNS::RR::EUI48; use Net::LDNS::RR::EUI64; use Net::LDNS::RR::GID; use Net::LDNS::RR::GPOS; use Net::LDNS::RR::HINFO; use Net::LDNS::RR::HIP; use Net::LDNS::RR::IPSECKEY; use Net::LDNS::RR::ISDN; use Net::LDNS::RR::KEY; use Net::LDNS::RR::KX; use Net::LDNS::RR::L32; use Net::LDNS::RR::L64; use Net::LDNS::RR::LOC; use Net::LDNS::RR::LP; use Net::LDNS::RR::MAILA; use Net::LDNS::RR::MAILB; use Net::LDNS::RR::MB; use Net::LDNS::RR::MD; use Net::LDNS::RR::MF; use Net::LDNS::RR::MG; use Net::LDNS::RR::MINFO; use Net::LDNS::RR::MR; use Net::LDNS::RR::MX; use Net::LDNS::RR::NAPTR; use Net::LDNS::RR::NID; use Net::LDNS::RR::NIMLOC; use Net::LDNS::RR::NINFO; use Net::LDNS::RR::NS; use Net::LDNS::RR::NSAP; use Net::LDNS::RR::NSEC; use Net::LDNS::RR::NSEC3; use Net::LDNS::RR::NSEC3PARAM; use Net::LDNS::RR::NULL; use Net::LDNS::RR::NXT; use Net::LDNS::RR::PTR; use Net::LDNS::RR::PX; use Net::LDNS::RR::RKEY; use Net::LDNS::RR::RP; use Net::LDNS::RR::RRSIG; use Net::LDNS::RR::RT; use Net::LDNS::RR::SINK; use Net::LDNS::RR::SOA; use Net::LDNS::RR::SPF; use Net::LDNS::RR::SRV; use Net::LDNS::RR::SSHFP; use Net::LDNS::RR::TA; use Net::LDNS::RR::TALINK; use Net::LDNS::RR::TKEY; use Net::LDNS::RR::TLSA; use Net::LDNS::RR::TXT; use Net::LDNS::RR::TYPE; use Net::LDNS::RR::UID; use Net::LDNS::RR::UINFO; use Net::LDNS::RR::UNSPEC; use Net::LDNS::RR::URI; use Net::LDNS::RR::WKS; use Net::LDNS::RR::X25; use Carp; use overload '<=>' => \&do_compare, 'cmp' => \&do_compare, '""' => \&to_string; sub new { my ( $class, $string ) = @_; if ( $string ) { return $class->new_from_string( $string ); } else { croak "Must provide string to create RR"; } } sub name { my ( $self ) = @_; return $self->owner; } sub do_compare { my ( $self, $other, $swapped ) = @_; return $self->compare( $other ); } sub to_string { my ( $self ) = @_; return $self->string; } 1; =head1 NAME Net::LDNS::RR - common baseclass for all classes representing resource records. =head1 SYNOPSIS my $rr = Net::LDNS::RR->new('www.iis.se IN A 91.226.36.46'); =head1 OVERLOADS This class overloads stringify and comparisons ('""', '<=>' and 'cmp'). =head1 CLASS METHOD =over =item new($string) Creates a new RR object of a suitable subclass, given a string representing an RR in common presentation format. =back =head1 INSTANCE METHODS =over =item owner() =item name() These two both return the owner name of the RR. =item ttl() Returns the ttl of the RR. =item type() Return the type of the RR. =item class() Returns the class of the RR. =item string() Returns a string with the RR in presentation format. =item do_compare($other) Calls the XS C method with the arguments it needs, rather than the ones overloading gives. =item to_string Calls the XS C method with the arguments it needs, rather than the ones overloading gives. Functionally identical to L from the Perl level, except for being a tiny little bit slower. =item rd_count() The number of RDATA objects in this RR. =item rdf($postion) The raw data of the RDATA object in the given position. The first item is in position 0. If an attempt is made to fetch RDATA from a position that doesn't have any, an exception will be thrown. =back Net-LDNS-0.75/lib/Net/LDNS/RRList.pm000644 000770 000024 00000000671 12257304173 017075 0ustar00calledstaff000000 000000 package Net::LDNS::RRList; 1; =head1 NAME Net::LDNS::RR - common baseclass for all classes representing resource records. =head1 SYNOPSIS my $rrlist = $packet->all; =head1 INSTANCE METHODS =over =item count() Returns the number of items in the list. =item push($rr) Pushes an RR onto the list. =item pop() Pops an RR off the list. =item is_rrset() Returns true or false depending on if the list is an RRset or not. =back Net-LDNS-0.75/lib/Net/LDNS/RR/A.pm000644 000770 000024 00000000477 12251573504 016425 0ustar00calledstaff000000 000000 package Net::LDNS::RR::A; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::A - Type A record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item address() Returns the address. =back Net-LDNS-0.75/lib/Net/LDNS/RR/A6.pm000644 000770 000024 00000000467 12251573505 016513 0ustar00calledstaff000000 000000 package Net::LDNS::RR::A6; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::A6 - Type A6 record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/AAAA.pm000644 000770 000024 00000000510 12251573505 016715 0ustar00calledstaff000000 000000 package Net::LDNS::RR::AAAA; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::AAAA - Type AAAA record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item address() Returns the address. =back Net-LDNS-0.75/lib/Net/LDNS/RR/AFSDB.pm000644 000770 000024 00000000500 12251573505 017050 0ustar00calledstaff000000 000000 package Net::LDNS::RR::AFSDB; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::AFSDB - Type AFSDB record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/APL.pm000644 000770 000024 00000000472 12251573505 016655 0ustar00calledstaff000000 000000 package Net::LDNS::RR::APL; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::APL - Type APL record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/ATMA.pm000644 000770 000024 00000000475 12251573505 016766 0ustar00calledstaff000000 000000 package Net::LDNS::RR::ATMA; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::ATMA - Type ATMA record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/CAA.pm000644 000770 000024 00000000472 12251573506 016626 0ustar00calledstaff000000 000000 package Net::LDNS::RR::CAA; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::CAA - Type CAA record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/CDS.pm000644 000770 000024 00000000472 12251573506 016653 0ustar00calledstaff000000 000000 package Net::LDNS::RR::CDS; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::CDS - Type CDS record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/CERT.pm000644 000770 000024 00000000475 12251573506 017002 0ustar00calledstaff000000 000000 package Net::LDNS::RR::CERT; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::CERT - Type CERT record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/CNAME.pm000644 000770 000024 00000000520 12251573506 017057 0ustar00calledstaff000000 000000 package Net::LDNS::RR::CNAME; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::CNAME - Type CNAME record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item cname() Returns the canonical name. =back Net-LDNS-0.75/lib/Net/LDNS/RR/DHCID.pm000644 000770 000024 00000000500 12251573506 017045 0ustar00calledstaff000000 000000 package Net::LDNS::RR::DHCID; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::DHCID - Type DHCID record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/DLV.pm000644 000770 000024 00000000472 12251573507 016670 0ustar00calledstaff000000 000000 package Net::LDNS::RR::DLV; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::DLV - Type DLV record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/DNAME.pm000644 000770 000024 00000000500 12251573507 017057 0ustar00calledstaff000000 000000 package Net::LDNS::RR::DNAME; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::DNAME - Type DNAME record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/DNSKEY.pm000644 000770 000024 00000002015 12314567436 017237 0ustar00calledstaff000000 000000 package Net::LDNS::RR::DNSKEY; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::DNSKEY - Type DNSKEY record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item flags() Returns the flag field as a number. =item protocol() Returns the protocol number. =item algorithm() Returns the algorithm number. =item keydata() Returns the cryptographic key in binary form. =item ds($hash) Returns a L record matching this key. The argument must be one of the strings 'sha1', 'sha256', 'sha384' or 'gost'. GOST may not be available, depending on how you ldns library was compiled. =item keysize() The size of the key stored in the record. For RSA variants, it's the length in bits of the prime number. For DSA variants, it's the key's "T" value (see RFC2536). For DH, it's the value of the "prime length" field (and probably useless, since DH keys can't have signature records). =back Net-LDNS-0.75/lib/Net/LDNS/RR/DS.pm000644 000770 000024 00000001447 12251573507 016554 0ustar00calledstaff000000 000000 package Net::LDNS::RR::DS; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::DS - Type DS record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item keytag() Returns the keytag value. =item digtype() Returns the numeric digest type. =item algorithm() Returns the algorithm number. =item digest() Returns the cryptographic digest in binary form. =item hexdigest() Returns the cryptographic digest as a hexadecimal string. =item verify($other) Checks if the current object is derived from the other object (if it's a DNSKEY) or was derived from the same DNSKEY as the other object (if it's a DS). If used with any other type of RR, it always returns false. =back Net-LDNS-0.75/lib/Net/LDNS/RR/EID.pm000644 000770 000024 00000000472 12251573507 016644 0ustar00calledstaff000000 000000 package Net::LDNS::RR::EID; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::EID - Type EID record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/EUI48.pm000644 000770 000024 00000000500 12251573510 017023 0ustar00calledstaff000000 000000 package Net::LDNS::RR::EUI48; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::EUI48 - Type EUI48 record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/EUI64.pm000644 000770 000024 00000000500 12251573510 017021 0ustar00calledstaff000000 000000 package Net::LDNS::RR::EUI64; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::EUI64 - Type EUI64 record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/GID.pm000644 000770 000024 00000000472 12251573510 016640 0ustar00calledstaff000000 000000 package Net::LDNS::RR::GID; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::GID - Type GID record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/GPOS.pm000644 000770 000024 00000000475 12251573510 017010 0ustar00calledstaff000000 000000 package Net::LDNS::RR::GPOS; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::GPOS - Type GPOS record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/HINFO.pm000644 000770 000024 00000000500 12251573510 017070 0ustar00calledstaff000000 000000 package Net::LDNS::RR::HINFO; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::HINFO - Type HINFO record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/HIP.pm000644 000770 000024 00000000472 12251573511 016656 0ustar00calledstaff000000 000000 package Net::LDNS::RR::HIP; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::HIP - Type HIP record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/IPSECKEY.pm000644 000770 000024 00000000511 12251573511 017444 0ustar00calledstaff000000 000000 package Net::LDNS::RR::IPSECKEY; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::IPSECKEY - Type IPSECKEY record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/ISDN.pm000644 000770 000024 00000000475 12251573511 016776 0ustar00calledstaff000000 000000 package Net::LDNS::RR::ISDN; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::ISDN - Type ISDN record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/KEY.pm000644 000770 000024 00000000764 12251573511 016672 0ustar00calledstaff000000 000000 package Net::LDNS::RR::KEY; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::KEY - Type KEY record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item flags() Returns the flag field as a number. =item protocol() Returns the protocol number. =item algorithm() Returns the algorithm number. =item keydata() Returns the cryptographic key in binary form. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/KX.pm000644 000770 000024 00000000467 12251573511 016564 0ustar00calledstaff000000 000000 package Net::LDNS::RR::KX; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::KX - Type KX record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/L32.pm000644 000770 000024 00000000472 12251573511 016576 0ustar00calledstaff000000 000000 package Net::LDNS::RR::L32; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::L32 - Type L32 record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/L64.pm000644 000770 000024 00000000472 12251573512 016604 0ustar00calledstaff000000 000000 package Net::LDNS::RR::L64; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::L64 - Type L64 record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/LOC.pm000644 000770 000024 00000000472 12251573512 016654 0ustar00calledstaff000000 000000 package Net::LDNS::RR::LOC; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::LOC - Type LOC record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/LP.pm000644 000770 000024 00000000467 12251573512 016556 0ustar00calledstaff000000 000000 package Net::LDNS::RR::LP; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::LP - Type LP record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/MAILA.pm000644 000770 000024 00000000500 12251573512 017052 0ustar00calledstaff000000 000000 package Net::LDNS::RR::MAILA; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::MAILA - Type MAILA record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/MAILB.pm000644 000770 000024 00000000500 12251573512 017053 0ustar00calledstaff000000 000000 package Net::LDNS::RR::MAILB; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::MAILB - Type MAILB record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/MB.pm000644 000770 000024 00000000467 12251573513 016542 0ustar00calledstaff000000 000000 package Net::LDNS::RR::MB; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::MB - Type MB record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/MD.pm000644 000770 000024 00000000467 12251573513 016544 0ustar00calledstaff000000 000000 package Net::LDNS::RR::MD; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::MD - Type MD record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/MF.pm000644 000770 000024 00000000467 12251573513 016546 0ustar00calledstaff000000 000000 package Net::LDNS::RR::MF; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::MF - Type MF record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/MG.pm000644 000770 000024 00000000467 12251573513 016547 0ustar00calledstaff000000 000000 package Net::LDNS::RR::MG; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::MG - Type MG record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/MINFO.pm000644 000770 000024 00000000500 12251573513 017100 0ustar00calledstaff000000 000000 package Net::LDNS::RR::MINFO; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::MINFO - Type MINFO record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/MR.pm000644 000770 000024 00000000467 12251573514 016563 0ustar00calledstaff000000 000000 package Net::LDNS::RR::MR; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::MR - Type MR record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/MX.pm000644 000770 000024 00000000624 12251573514 016564 0ustar00calledstaff000000 000000 package Net::LDNS::RR::MX; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::MX - Type MX record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item exchange() Returns the name of the mail server. =item preference() Returns the preference value of the record. =back Net-LDNS-0.75/lib/Net/LDNS/RR/NAPTR.pm000644 000770 000024 00000000500 12251573514 017115 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NAPTR; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::NAPTR - Type NAPTR record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/NID.pm000644 000770 000024 00000000472 12251573514 016653 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NID; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::NID - Type NID record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/NIMLOC.pm000644 000770 000024 00000000503 12251573514 017215 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NIMLOC; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::NIMLOC - Type NIMLOC record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/NINFO.pm000644 000770 000024 00000000500 12251573515 017103 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NINFO; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::NINFO - Type NINFO record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/NS.pm000644 000770 000024 00000000521 12251573515 016555 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NS; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::NS - Type NS record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item nsdname() Returns the name of the nameserver. =back Net-LDNS-0.75/lib/Net/LDNS/RR/NSAP.pm000644 000770 000024 00000000475 12251573515 017006 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NSAP; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::NSAP - Type NSAP record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/NSEC.pm000644 000770 000024 00000001524 12321445747 016774 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NSEC; use parent 'Net::LDNS::RR'; sub nxtdname { return $_[0]->next; } 1; =head1 NAME Net::LDNS::RR::NSEC - Type NSEC record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item next() Returns the next name. =item nxtdname() Alias for C. =item typelist() Returns a string with the typelist. The string has the type names separated by spaces. =item typehref() Returns a reference to a hash, where the keys are the type names and the corresponding values are true. That is, if you look for a type in this hash you get a true value back if the record covers it and false if not. =item covers($name) Returns true or false depending on if the record covers the given name or not. =back Net-LDNS-0.75/lib/Net/LDNS/RR/NSEC3.pm000644 000770 000024 00000001557 12321445741 017057 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NSEC3; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::NSEC3 - Type NSEC3 record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item algorithm() Returns the algorithm number. =item flags() Returns the flags field. =item optout() Returns the optout flag. =item iterations() Returns the iteration count. =item salt() Returns the cryptographic salt, in binary form. =item next_owner() Returns the next owner field. =item typelist() Returns the typelist as a space-separated string. =item typehref() Returns the typelist as a reference to a hash where the included types are keys storing true values. =item covers($name) Returns true or false depending on if the record covers the given name or not. =back Net-LDNS-0.75/lib/Net/LDNS/RR/NSEC3PARAM.pm000644 000770 000024 00000000776 12251573516 017646 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NSEC3PARAM; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::NSEC3PARAM - Type NSEC3PARAM record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item algorithm() Returns the algorithm number. =item flags() Returns the flags field. =item iterations() Returns the iteration count. =item salt() Returns the cryptographic salt in binary form. =back Net-LDNS-0.75/lib/Net/LDNS/RR/NULL.pm000644 000770 000024 00000000475 12251573516 017020 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NULL; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::NULL - Type NULL record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/NXT.pm000644 000770 000024 00000000472 12251573516 016714 0ustar00calledstaff000000 000000 package Net::LDNS::RR::NXT; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::NXT - Type NXT record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/PTR.pm000644 000770 000024 00000000512 12251573516 016703 0ustar00calledstaff000000 000000 package Net::LDNS::RR::PTR; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::PTR - Type PTR record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item ptrdname() Returns the domain name. =back Net-LDNS-0.75/lib/Net/LDNS/RR/PX.pm000644 000770 000024 00000000467 12251573516 016576 0ustar00calledstaff000000 000000 package Net::LDNS::RR::PX; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::PX - Type PX record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/RKEY.pm000644 000770 000024 00000000475 12251573517 017021 0ustar00calledstaff000000 000000 package Net::LDNS::RR::RKEY; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::RKEY - Type RKEY record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/RP.pm000644 000770 000024 00000000467 12251573517 016571 0ustar00calledstaff000000 000000 package Net::LDNS::RR::RP; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::RP - Type RP record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/RRSIG.pm000644 000770 000024 00000004440 12252046515 017123 0ustar00calledstaff000000 000000 package Net::LDNS::RR::RRSIG; use parent 'Net::LDNS::RR'; sub verify { my ( $self, $rrset, $keys ) = @_; my $msg = ''; return $self->verify_time( $rrset, $keys, time(), $msg ); } sub verify_str { my ( $self, $rrset, $keys ) = @_; my $msg = ''; $self->verify_time( $rrset, $keys, time(), $msg ); return $msg; } 1; =head1 NAME Net::LDNS::RR::RRSIG - Type RRSIG record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item typecovered() Returns a string with the name of the RR type this signature covers. =item algorithm() Returns the algorithm number. =item labels() Returns the number of labels that was used to calculate the signature. =item origttl() Returns the original TTL value. =item expiration() Returns the expiration time, as a time_t. =item inception() Returns the inception time, as a time_t. =item keytag() Returns the keytag. =item signer() Returns the signer name. =item signature() Returns the cryptographic signture in binary form. =item verify($rrset_ref, $key_ref) Cryptographically verifies that the signature in this object matches the given RRset and at least one of the given keys. C<$rrset_ref> should be a reference to an array of RR objects, and C<$key_ref> a reference to an array of L objects. This method simply returns a true or false value, depending on the result och the check. =item verify_str($rrset_ref, $key_ref) Takes exactly the same arguments as L and performs the same action, but instead of true/false it returns a string describing the result. In the case of a successful result the message will be "All OK". For negative results, the string will describe the reason the verification failed. =item verify_time($rrset_ref, $key_ref, $time, $msg) This is the XS method doing the work for the previous two methods. C<$rrset_ref> and C<$key_ref> are the same as for the other methods. C<$time> is the C value for which the validation should be made (for the previous two methods it is set to the current computer time). C<$msg> should be a writable scalar, and the string message describing the result will be but in it. The return value from the method is true/false. =back Net-LDNS-0.75/lib/Net/LDNS/RR/RT.pm000644 000770 000024 00000000467 12251573517 016575 0ustar00calledstaff000000 000000 package Net::LDNS::RR::RT; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::RT - Type RT record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/SIG.pm000644 000770 000024 00000001507 12251573517 016666 0ustar00calledstaff000000 000000 package Net::LDNS::RR::SIG; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::SIG - Type SIG record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item typecovered() Returns a string with the name of the RR type this signature covers. =item algorithm() Returns the algorithm number. =item labels() Returns the number of labels that was used to calculate the signature. =item origttl() Returns the original TTL value. =item expiration() Returns the expiration time, as a time_t. =item inception() Returns the inception time, as a time_t. =item keytag() Returns the keytag. =item signer() Returns the signer name. =item signature() Returns the cryptographic signture in binary form. =back Net-LDNS-0.75/lib/Net/LDNS/RR/SINK.pm000644 000770 000024 00000000475 12251573520 017005 0ustar00calledstaff000000 000000 package Net::LDNS::RR::SINK; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::SINK - Type SINK record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/SOA.pm000644 000770 000024 00000001066 12251573520 016660 0ustar00calledstaff000000 000000 package Net::LDNS::RR::SOA; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::SOA - Type SOA record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item mname() Returns the master server name. =item rname() Returns the contact mail address, in DNAME format. =item serial() Returns the serial number. =item refresh() =item retry() =item refresh() =item minimum() Returns the respective timing values from the record. =back Net-LDNS-0.75/lib/Net/LDNS/RR/SPF.pm000644 000770 000024 00000000511 12251573520 016660 0ustar00calledstaff000000 000000 package Net::LDNS::RR::SPF; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::SPF - Type SPF record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item spfdata() Returns the SPF string. =back Net-LDNS-0.75/lib/Net/LDNS/RR/SRV.pm000644 000770 000024 00000000472 12251573520 016710 0ustar00calledstaff000000 000000 package Net::LDNS::RR::SRV; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::SRV - Type SRV record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/SSHFP.pm000644 000770 000024 00000000500 12251573520 017111 0ustar00calledstaff000000 000000 package Net::LDNS::RR::SSHFP; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::SSHFP - Type SSHFP record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/TA.pm000644 000770 000024 00000000467 12251573520 016546 0ustar00calledstaff000000 000000 package Net::LDNS::RR::TA; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::TA - Type TA record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/TALINK.pm000644 000770 000024 00000000503 12251573521 017214 0ustar00calledstaff000000 000000 package Net::LDNS::RR::TALINK; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::TALINK - Type TALINK record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/TKEY.pm000644 000770 000024 00000000475 12251573521 017016 0ustar00calledstaff000000 000000 package Net::LDNS::RR::TKEY; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::TKEY - Type TKEY record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/TLSA.pm000644 000770 000024 00000000475 12251573521 017005 0ustar00calledstaff000000 000000 package Net::LDNS::RR::TLSA; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::TLSA - Type TLSA record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/TXT.pm000644 000770 000024 00000000507 12251573521 016715 0ustar00calledstaff000000 000000 package Net::LDNS::RR::TXT; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::TXT - Type TXT record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS =over =item txtdata() Returns the text data. =back Net-LDNS-0.75/lib/Net/LDNS/RR/TYPE.pm000644 000770 000024 00000000475 12251573521 017023 0ustar00calledstaff000000 000000 package Net::LDNS::RR::TYPE; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::TYPE - Type TYPE record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/UID.pm000644 000770 000024 00000000472 12251573522 016661 0ustar00calledstaff000000 000000 package Net::LDNS::RR::UID; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::UID - Type UID record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/UINFO.pm000644 000770 000024 00000000500 12251573522 017110 0ustar00calledstaff000000 000000 package Net::LDNS::RR::UINFO; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::UINFO - Type UINFO record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/UNSPEC.pm000644 000770 000024 00000000503 12251573522 017230 0ustar00calledstaff000000 000000 package Net::LDNS::RR::UNSPEC; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::UNSPEC - Type UNSPEC record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/URI.pm000644 000770 000024 00000000472 12251573522 016677 0ustar00calledstaff000000 000000 package Net::LDNS::RR::URI; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::URI - Type URI record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/WKS.pm000644 000770 000024 00000000472 12251573522 016704 0ustar00calledstaff000000 000000 package Net::LDNS::RR::WKS; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::WKS - Type WKS record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/lib/Net/LDNS/RR/X25.pm000644 000770 000024 00000000472 12251573523 016617 0ustar00calledstaff000000 000000 package Net::LDNS::RR::X25; use parent 'Net::LDNS::RR'; 1; =head1 NAME Net::LDNS::RR::X25 - Type X25 record =head1 DESCRIPTION A subclass of L, so it has all the methods of that class available in addition to the ones documented here. =head1 METHODS No RDATA methods implemented yet. =cut Net-LDNS-0.75/include/ldns/000755 000770 000024 00000000000 12510741546 015704 5ustar00calledstaff000000 000000 Net-LDNS-0.75/include/LDNS.h000644 000770 000024 00000010220 12503002543 015635 0ustar00calledstaff000000 000000 #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #define NEED_newSVpvn_share #define NEED_sv_2pv_flags #define NEED_newRV_noinc #include "ppport.h" #include #include #include #include #ifdef WE_CAN_HAZ_IDN #include #endif /* ldns 1.6.17 does not have this in its header files, but it is in the published documentation and we need it */ /* It looks like 1.6.18 will have it, but we'll fix that when it happens. */ #if (LDNS_REVISION) >= ((1<<16)|(6<<8)|(17)) void ldns_axfr_abort(ldns_resolver *obj); #endif typedef ldns_resolver *Net__LDNS; typedef ldns_pkt *Net__LDNS__Packet; typedef ldns_rr_list *Net__LDNS__RRList; typedef ldns_rr *Net__LDNS__RR; typedef ldns_rr *Net__LDNS__RR__A; typedef ldns_rr *Net__LDNS__RR__A6; typedef ldns_rr *Net__LDNS__RR__AAAA; typedef ldns_rr *Net__LDNS__RR__AFSDB; typedef ldns_rr *Net__LDNS__RR__APL; typedef ldns_rr *Net__LDNS__RR__ATMA; typedef ldns_rr *Net__LDNS__RR__CAA; typedef ldns_rr *Net__LDNS__RR__CDS; typedef ldns_rr *Net__LDNS__RR__CERT; typedef ldns_rr *Net__LDNS__RR__CNAME; typedef ldns_rr *Net__LDNS__RR__DHCID; typedef ldns_rr *Net__LDNS__RR__DLV; typedef ldns_rr *Net__LDNS__RR__DNAME; typedef ldns_rr *Net__LDNS__RR__DNSKEY; typedef ldns_rr *Net__LDNS__RR__DS; typedef ldns_rr *Net__LDNS__RR__EID; typedef ldns_rr *Net__LDNS__RR__EUI48; typedef ldns_rr *Net__LDNS__RR__EUI64; typedef ldns_rr *Net__LDNS__RR__GID; typedef ldns_rr *Net__LDNS__RR__GPOS; typedef ldns_rr *Net__LDNS__RR__HINFO; typedef ldns_rr *Net__LDNS__RR__HIP; typedef ldns_rr *Net__LDNS__RR__IPSECKEY; typedef ldns_rr *Net__LDNS__RR__ISDN; typedef ldns_rr *Net__LDNS__RR__KEY; typedef ldns_rr *Net__LDNS__RR__KX; typedef ldns_rr *Net__LDNS__RR__L32; typedef ldns_rr *Net__LDNS__RR__L64; typedef ldns_rr *Net__LDNS__RR__LOC; typedef ldns_rr *Net__LDNS__RR__LP; typedef ldns_rr *Net__LDNS__RR__MAILA; typedef ldns_rr *Net__LDNS__RR__MAILB; typedef ldns_rr *Net__LDNS__RR__MB; typedef ldns_rr *Net__LDNS__RR__MD; typedef ldns_rr *Net__LDNS__RR__MF; typedef ldns_rr *Net__LDNS__RR__MG; typedef ldns_rr *Net__LDNS__RR__MINFO; typedef ldns_rr *Net__LDNS__RR__MR; typedef ldns_rr *Net__LDNS__RR__MX; typedef ldns_rr *Net__LDNS__RR__NAPTR; typedef ldns_rr *Net__LDNS__RR__NID; typedef ldns_rr *Net__LDNS__RR__NIMLOC; typedef ldns_rr *Net__LDNS__RR__NINFO; typedef ldns_rr *Net__LDNS__RR__NS; typedef ldns_rr *Net__LDNS__RR__NSAP; typedef ldns_rr *Net__LDNS__RR__NSEC; typedef ldns_rr *Net__LDNS__RR__NSEC3; typedef ldns_rr *Net__LDNS__RR__NSEC3PARAM; typedef ldns_rr *Net__LDNS__RR__NULL; typedef ldns_rr *Net__LDNS__RR__NXT; typedef ldns_rr *Net__LDNS__RR__PTR; typedef ldns_rr *Net__LDNS__RR__PX; typedef ldns_rr *Net__LDNS__RR__RKEY; typedef ldns_rr *Net__LDNS__RR__RP; typedef ldns_rr *Net__LDNS__RR__RRSIG; typedef ldns_rr *Net__LDNS__RR__RT; typedef ldns_rr *Net__LDNS__RR__SIG; typedef ldns_rr *Net__LDNS__RR__SINK; typedef ldns_rr *Net__LDNS__RR__SOA; typedef ldns_rr *Net__LDNS__RR__SPF; typedef ldns_rr *Net__LDNS__RR__SRV; typedef ldns_rr *Net__LDNS__RR__SSHFP; typedef ldns_rr *Net__LDNS__RR__TA; typedef ldns_rr *Net__LDNS__RR__TALINK; typedef ldns_rr *Net__LDNS__RR__TKEY; typedef ldns_rr *Net__LDNS__RR__TLSA; typedef ldns_rr *Net__LDNS__RR__TXT; typedef ldns_rr *Net__LDNS__RR__TYPE; typedef ldns_rr *Net__LDNS__RR__UID; typedef ldns_rr *Net__LDNS__RR__UINFO; typedef ldns_rr *Net__LDNS__RR__UNSPEC; typedef ldns_rr *Net__LDNS__RR__URI; typedef ldns_rr *Net__LDNS__RR__WKS; typedef ldns_rr *Net__LDNS__RR__X25; #define D_STRING(what,where) ldns_rdf2str(ldns_rr_rdf(what,where)) #define D_U8(what,where) ldns_rdf2native_int8(ldns_rr_rdf(what,where)) #define D_U16(what,where) ldns_rdf2native_int16(ldns_rr_rdf(what,where)) #define D_U32(what,where) ldns_rdf2native_int32(ldns_rr_rdf(what,where)) SV *rr2sv(ldns_rr *rr); char *randomize_capitalization(char *in); #ifdef USE_ITHREADS void net_ldns_remember_resolver(SV *rv); void net_ldns_remember_rr(SV *rv); void net_ldns_remember_rrlist(SV *rv); void net_ldns_remember_packet(SV *rv); void net_ldns_remember(SV *rv, const char *hashname); void net_ldns_forget(); void net_ldns_clone_resolvers(); void net_ldns_clone_rrs(); void net_ldns_clone_rrlists(); void net_ldns_clone_packets(); #endifNet-LDNS-0.75/include/ldns/buffer.h000644 000770 000024 00000040411 12471046240 017321 0ustar00calledstaff000000 000000 /* * buffer.h -- generic memory buffer. * * Copyright (c) 2005-2008, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * * The buffer module implements a generic buffer. The API is based on * the java.nio.Buffer interface. */ #ifndef LDNS_BUFFER_H #define LDNS_BUFFER_H #include #include #include #include #include #include "ldns/util.h" #ifdef __cplusplus extern "C" { #endif /** * number of initial bytes in buffer of * which we cannot tell the size before hand */ #define LDNS_MIN_BUFLEN 512 /** * \file buffer.h * * This file contains the definition of ldns_buffer, and functions to manipulate those. */ /** * implementation of buffers to ease operations * * ldns_buffers can contain arbitrary information, per octet. You can write * to the current end of a buffer, read from the current position, and * access any data within it. * * Example use of buffers is in the source code of \ref host2str.c */ struct ldns_struct_buffer { /** The current position used for reading/writing */ size_t _position; /** The read/write limit */ size_t _limit; /** The amount of data the buffer can contain */ size_t _capacity; /** The data contained in the buffer */ uint8_t *_data; /** If the buffer is fixed it cannot be resized */ unsigned _fixed : 1; /** The current state of the buffer. If writing to the buffer fails * for any reason, this value is changed. This way, you can perform * multiple writes in sequence and check for success afterwards. */ ldns_status _status; }; typedef struct ldns_struct_buffer ldns_buffer; #ifdef NDEBUG INLINE void ldns_buffer_invariant(ldns_buffer *ATTR_UNUSED(buffer)) { } #else INLINE void ldns_buffer_invariant(ldns_buffer *buffer) { assert(buffer != NULL); assert(buffer->_position <= buffer->_limit); assert(buffer->_limit <= buffer->_capacity); assert(buffer->_data != NULL); } #endif /** * creates a new buffer with the specified capacity. * * \param[in] capacity the size (in bytes) to allocate for the buffer * \return the created buffer */ ldns_buffer *ldns_buffer_new(size_t capacity); /** * creates a buffer with the specified data. The data IS copied * and MEMORY allocations are done. The buffer is not fixed and can * be resized using buffer_reserve(). * * \param[in] buffer pointer to the buffer to put the data in * \param[in] data the data to encapsulate in the buffer * \param[in] size the size of the data */ void ldns_buffer_new_frm_data(ldns_buffer *buffer, void *data, size_t size); /** * clears the buffer and make it ready for writing. The buffer's limit * is set to the capacity and the position is set to 0. * \param[in] buffer the buffer to clear */ INLINE void ldns_buffer_clear(ldns_buffer *buffer) { ldns_buffer_invariant(buffer); /* reset status here? */ buffer->_position = 0; buffer->_limit = buffer->_capacity; } /** * makes the buffer ready for reading the data that has been written to * the buffer. The buffer's limit is set to the current position and * the position is set to 0. * * \param[in] buffer the buffer to flip * \return void */ INLINE void ldns_buffer_flip(ldns_buffer *buffer) { ldns_buffer_invariant(buffer); buffer->_limit = buffer->_position; buffer->_position = 0; } /** * make the buffer ready for re-reading the data. The buffer's * position is reset to 0. * \param[in] buffer the buffer to rewind */ INLINE void ldns_buffer_rewind(ldns_buffer *buffer) { ldns_buffer_invariant(buffer); buffer->_position = 0; } /** * returns the current position in the buffer (as a number of bytes) * \param[in] buffer the buffer * \return the current position */ INLINE size_t ldns_buffer_position(ldns_buffer *buffer) { return buffer->_position; } /** * sets the buffer's position to MARK. The position must be less than * or equal to the buffer's limit. * \param[in] buffer the buffer * \param[in] mark the mark to use */ INLINE void ldns_buffer_set_position(ldns_buffer *buffer, size_t mark) { assert(mark <= buffer->_limit); buffer->_position = mark; } /** * changes the buffer's position by COUNT bytes. The position must not * be moved behind the buffer's limit or before the beginning of the * buffer. * \param[in] buffer the buffer * \param[in] count the count to use */ INLINE void ldns_buffer_skip(ldns_buffer *buffer, ssize_t count) { assert(buffer->_position + count <= buffer->_limit); buffer->_position += count; } /** * returns the maximum size of the buffer * \param[in] buffer * \return the size */ INLINE size_t ldns_buffer_limit(ldns_buffer *buffer) { return buffer->_limit; } /** * changes the buffer's limit. If the buffer's position is greater * than the new limit the position is set to the limit. * \param[in] buffer the buffer * \param[in] limit the new limit */ INLINE void ldns_buffer_set_limit(ldns_buffer *buffer, size_t limit) { assert(limit <= buffer->_capacity); buffer->_limit = limit; if (buffer->_position > buffer->_limit) buffer->_position = buffer->_limit; } /** * returns the number of bytes the buffer can hold. * \param[in] buffer the buffer * \return the number of bytes */ INLINE size_t ldns_buffer_capacity(ldns_buffer *buffer) { return buffer->_capacity; } /** * changes the buffer's capacity. The data is reallocated so any * pointers to the data may become invalid. The buffer's limit is set * to the buffer's new capacity. * \param[in] buffer the buffer * \param[in] capacity the capacity to use * \return whether this failed or succeeded */ bool ldns_buffer_set_capacity(ldns_buffer *buffer, size_t capacity); /** * ensures BUFFER can contain at least AMOUNT more bytes. The buffer's * capacity is increased if necessary using buffer_set_capacity(). * * The buffer's limit is always set to the (possibly increased) * capacity. * \param[in] buffer the buffer * \param[in] amount amount to use * \return whether this failed or succeeded */ bool ldns_buffer_reserve(ldns_buffer *buffer, size_t amount); /** * returns a pointer to the data at the indicated position. * \param[in] buffer the buffer * \param[in] at position * \return the pointer to the data */ INLINE uint8_t * ldns_buffer_at(const ldns_buffer *buffer, size_t at) { assert(at <= buffer->_limit); return buffer->_data + at; } /** * returns a pointer to the beginning of the buffer (the data at * position 0). * \param[in] buffer the buffer * \return the pointer */ INLINE uint8_t * ldns_buffer_begin(const ldns_buffer *buffer) { return ldns_buffer_at(buffer, 0); } /** * returns a pointer to the end of the buffer (the data at the buffer's * limit). * \param[in] buffer the buffer * \return the pointer */ INLINE uint8_t * ldns_buffer_end(ldns_buffer *buffer) { return ldns_buffer_at(buffer, buffer->_limit); } /** * returns a pointer to the data at the buffer's current position. * \param[in] buffer the buffer * \return the pointer */ INLINE uint8_t * ldns_buffer_current(ldns_buffer *buffer) { return ldns_buffer_at(buffer, buffer->_position); } /** * returns the number of bytes remaining between the indicated position and * the limit. * \param[in] buffer the buffer * \param[in] at indicated position * \return number of bytes */ INLINE size_t ldns_buffer_remaining_at(ldns_buffer *buffer, size_t at) { ldns_buffer_invariant(buffer); assert(at <= buffer->_limit); return buffer->_limit - at; } /** * returns the number of bytes remaining between the buffer's position and * limit. * \param[in] buffer the buffer * \return the number of bytes */ INLINE size_t ldns_buffer_remaining(ldns_buffer *buffer) { return ldns_buffer_remaining_at(buffer, buffer->_position); } /** * checks if the buffer has at least COUNT more bytes available. * Before reading or writing the caller needs to ensure enough space * is available! * \param[in] buffer the buffer * \param[in] at indicated position * \param[in] count how much is available * \return true or false (as int?) */ INLINE int ldns_buffer_available_at(ldns_buffer *buffer, size_t at, size_t count) { return count <= ldns_buffer_remaining_at(buffer, at); } /** * checks if the buffer has count bytes available at the current position * \param[in] buffer the buffer * \param[in] count how much is available * \return true or false (as int?) */ INLINE int ldns_buffer_available(ldns_buffer *buffer, size_t count) { return ldns_buffer_available_at(buffer, buffer->_position, count); } /** * writes the given data to the buffer at the specified position * \param[in] buffer the buffer * \param[in] at the position (in number of bytes) to write the data at * \param[in] data pointer to the data to write to the buffer * \param[in] count the number of bytes of data to write */ INLINE void ldns_buffer_write_at(ldns_buffer *buffer, size_t at, const void *data, size_t count) { assert(ldns_buffer_available_at(buffer, at, count)); memcpy(buffer->_data + at, data, count); } /** * writes count bytes of data to the current position of the buffer * \param[in] buffer the buffer * \param[in] data the data to write * \param[in] count the lenght of the data to write */ INLINE void ldns_buffer_write(ldns_buffer *buffer, const void *data, size_t count) { ldns_buffer_write_at(buffer, buffer->_position, data, count); buffer->_position += count; } /** * copies the given (null-delimited) string to the specified position at the buffer * \param[in] buffer the buffer * \param[in] at the position in the buffer * \param[in] str the string to write */ INLINE void ldns_buffer_write_string_at(ldns_buffer *buffer, size_t at, const char *str) { ldns_buffer_write_at(buffer, at, str, strlen(str)); } /** * copies the given (null-delimited) string to the current position at the buffer * \param[in] buffer the buffer * \param[in] str the string to write */ INLINE void ldns_buffer_write_string(ldns_buffer *buffer, const char *str) { ldns_buffer_write(buffer, str, strlen(str)); } /** * writes the given byte of data at the given position in the buffer * \param[in] buffer the buffer * \param[in] at the position in the buffer * \param[in] data the 8 bits to write */ INLINE void ldns_buffer_write_u8_at(ldns_buffer *buffer, size_t at, uint8_t data) { assert(ldns_buffer_available_at(buffer, at, sizeof(data))); buffer->_data[at] = data; } /** * writes the given byte of data at the current position in the buffer * \param[in] buffer the buffer * \param[in] data the 8 bits to write */ INLINE void ldns_buffer_write_u8(ldns_buffer *buffer, uint8_t data) { ldns_buffer_write_u8_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } /** * writes the given 2 byte integer at the given position in the buffer * \param[in] buffer the buffer * \param[in] at the position in the buffer * \param[in] data the 16 bits to write */ INLINE void ldns_buffer_write_u16_at(ldns_buffer *buffer, size_t at, uint16_t data) { assert(ldns_buffer_available_at(buffer, at, sizeof(data))); ldns_write_uint16(buffer->_data + at, data); } /** * writes the given 2 byte integer at the current position in the buffer * \param[in] buffer the buffer * \param[in] data the 16 bits to write */ INLINE void ldns_buffer_write_u16(ldns_buffer *buffer, uint16_t data) { ldns_buffer_write_u16_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } /** * writes the given 4 byte integer at the given position in the buffer * \param[in] buffer the buffer * \param[in] at the position in the buffer * \param[in] data the 32 bits to write */ INLINE void ldns_buffer_write_u32_at(ldns_buffer *buffer, size_t at, uint32_t data) { assert(ldns_buffer_available_at(buffer, at, sizeof(data))); ldns_write_uint32(buffer->_data + at, data); } /** * writes the given 4 byte integer at the current position in the buffer * \param[in] buffer the buffer * \param[in] data the 32 bits to write */ INLINE void ldns_buffer_write_u32(ldns_buffer *buffer, uint32_t data) { ldns_buffer_write_u32_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } /** * copies count bytes of data at the given position to the given data-array * \param[in] buffer the buffer * \param[in] at the position in the buffer to start * \param[out] data buffer to copy to * \param[in] count the length of the data to copy */ INLINE void ldns_buffer_read_at(ldns_buffer *buffer, size_t at, void *data, size_t count) { assert(ldns_buffer_available_at(buffer, at, count)); memcpy(data, buffer->_data + at, count); } /** * copies count bytes of data at the current position to the given data-array * \param[in] buffer the buffer * \param[out] data buffer to copy to * \param[in] count the length of the data to copy */ INLINE void ldns_buffer_read(ldns_buffer *buffer, void *data, size_t count) { ldns_buffer_read_at(buffer, buffer->_position, data, count); buffer->_position += count; } /** * returns the byte value at the given position in the buffer * \param[in] buffer the buffer * \param[in] at the position in the buffer * \return 1 byte integer */ INLINE uint8_t ldns_buffer_read_u8_at(ldns_buffer *buffer, size_t at) { assert(ldns_buffer_available_at(buffer, at, sizeof(uint8_t))); return buffer->_data[at]; } /** * returns the byte value at the current position in the buffer * \param[in] buffer the buffer * \return 1 byte integer */ INLINE uint8_t ldns_buffer_read_u8(ldns_buffer *buffer) { uint8_t result = ldns_buffer_read_u8_at(buffer, buffer->_position); buffer->_position += sizeof(uint8_t); return result; } /** * returns the 2-byte integer value at the given position in the buffer * \param[in] buffer the buffer * \param[in] at position in the buffer * \return 2 byte integer */ INLINE uint16_t ldns_buffer_read_u16_at(ldns_buffer *buffer, size_t at) { assert(ldns_buffer_available_at(buffer, at, sizeof(uint16_t))); return ldns_read_uint16(buffer->_data + at); } /** * returns the 2-byte integer value at the current position in the buffer * \param[in] buffer the buffer * \return 2 byte integer */ INLINE uint16_t ldns_buffer_read_u16(ldns_buffer *buffer) { uint16_t result = ldns_buffer_read_u16_at(buffer, buffer->_position); buffer->_position += sizeof(uint16_t); return result; } /** * returns the 4-byte integer value at the given position in the buffer * \param[in] buffer the buffer * \param[in] at position in the buffer * \return 4 byte integer */ INLINE uint32_t ldns_buffer_read_u32_at(ldns_buffer *buffer, size_t at) { assert(ldns_buffer_available_at(buffer, at, sizeof(uint32_t))); return ldns_read_uint32(buffer->_data + at); } /** * returns the 4-byte integer value at the current position in the buffer * \param[in] buffer the buffer * \return 4 byte integer */ INLINE uint32_t ldns_buffer_read_u32(ldns_buffer *buffer) { uint32_t result = ldns_buffer_read_u32_at(buffer, buffer->_position); buffer->_position += sizeof(uint32_t); return result; } /** * returns the status of the buffer * \param[in] buffer * \return the status */ INLINE ldns_status ldns_buffer_status(ldns_buffer *buffer) { return buffer->_status; } /** * returns true if the status of the buffer is LDNS_STATUS_OK, false otherwise * \param[in] buffer the buffer * \return true or false */ INLINE bool ldns_buffer_status_ok(ldns_buffer *buffer) { if (buffer) { return ldns_buffer_status(buffer) == LDNS_STATUS_OK; } else { return false; } } /** * prints to the buffer, increasing the capacity if required using * buffer_reserve(). The buffer's position is set to the terminating '\\0' * Returns the number of characters written (not including the * terminating '\\0') or -1 on failure. */ int ldns_buffer_printf(ldns_buffer *buffer, const char *format, ...); /* ATTR_FORMAT(printf, 2, 3);*/ /** * frees the buffer. * \param[in] *buffer the buffer to be freed * \return void */ void ldns_buffer_free(ldns_buffer *buffer); /** * Makes the buffer fixed and returns a pointer to the data. The * caller is responsible for free'ing the result. * \param[in] *buffer the buffer to be exported * \return void */ void *ldns_buffer_export(ldns_buffer *buffer); /** * Copy contents of the from buffer to the result buffer and then flips * the result buffer. Data will be silently truncated if the result buffer is * too small. * \param[out] *result resulting buffer which is copied to. * \param[in] *from what to copy to result. */ void ldns_buffer_copy(ldns_buffer* result, ldns_buffer* from); #ifdef __cplusplus } #endif #endif /* LDNS_BUFFER_H */ Net-LDNS-0.75/include/ldns/common.h000644 000770 000024 00000004235 12471046240 017344 0ustar00calledstaff000000 000000 /** * \file common.h * * Common definitions for LDNS */ /** * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ #ifndef LDNS_COMMON_H #define LDNS_COMMON_H /* * The build configuration that is used in the distributed headers, * as detected and determined by the auto configure script. */ #define LDNS_BUILD_CONFIG_HAVE_SSL 1 #define LDNS_BUILD_CONFIG_HAVE_INTTYPES_H 1 #define LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT 1 #define LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED 1 #define LDNS_BUILD_CONFIG_HAVE_SOCKLEN_T 1 #define LDNS_BUILD_CONFIG_USE_DANE 1 #define LDNS_BUILD_CONFIG_HAVE_B32_PTON 0 #define LDNS_BUILD_CONFIG_HAVE_B32_NTOP 0 /* * HAVE_STDBOOL_H is not available when distributed as a library, but no build * configuration variables may be used (like those above) because the header * is sometimes only available when using special compiler flags to enable the * c99 environment. Because we cannot force the usage of this flag, we have to * provide a default type. Below what is suggested by the autoconf manual. */ /*@ignore@*/ /* splint barfs on this construct */ #ifndef __bool_true_false_are_defined # ifdef HAVE_STDBOOL_H # include # else # ifndef HAVE__BOOL # ifdef __cplusplus typedef bool _Bool; # else # define _Bool signed char # endif # endif # define bool _Bool # define false 0 # define true 1 # define __bool_true_false_are_defined 1 # endif #endif /*@end@*/ #if LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT #define ATTR_FORMAT(archetype, string_index, first_to_check) \ __attribute__ ((format (archetype, string_index, first_to_check))) #else /* !LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT */ #define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */ #endif /* !LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT */ #if defined(__cplusplus) #define ATTR_UNUSED(x) #elif LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED #define ATTR_UNUSED(x) x __attribute__((unused)) #else /* !LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED */ #define ATTR_UNUSED(x) x #endif /* !LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED */ #if !LDNS_BUILD_CONFIG_HAVE_SOCKLEN_T typedef int socklen_t; #endif #endif /* LDNS_COMMON_H */ Net-LDNS-0.75/include/ldns/config.h000644 000770 000024 00000035051 12502502027 017314 0ustar00calledstaff000000 000000 #include "EXTERN.h" #include "perl.h" /* Define if building universal (internal helper macro) */ /* #undef AC_APPLE_UNIVERSAL_BUILD */ /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 /* Whether the C compiler accepts the "format" attribute */ #define HAVE_ATTR_FORMAT 1 /* Whether the C compiler accepts the "unused" attribute */ #define HAVE_ATTR_UNUSED 1 /* Define to 1 if you have the `b32_ntop' function. */ /* #undef HAVE_B32_NTOP */ /* Define to 1 if you have the `b32_pton' function. */ /* #undef HAVE_B32_PTON */ /* Define to 1 if you have the `b64_ntop' function. */ /* #undef HAVE_B64_NTOP */ /* Define to 1 if you have the `b64_pton' function. */ /* #undef HAVE_B64_PTON */ /* Define to 1 if you have the `bzero' function. */ #define HAVE_BZERO 1 /* Define to 1 if you have the `calloc' function. */ #define HAVE_CALLOC 1 /* Define to 1 if you have the `ctime_r' function. */ #define HAVE_CTIME_R 1 /* Is a CAFILE given at configure time */ #define HAVE_DANE_CA_FILE 0 /* Is a CAPATH given at configure time */ #define HAVE_DANE_CA_PATH 0 /* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you don't. */ #define HAVE_DECL_NID_SECP384R1 1 /* Define to 1 if you have the declaration of `NID_X9_62_prime256v1', and to 0 if you don't. */ #define HAVE_DECL_NID_X9_62_PRIME256V1 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the `endprotoent' function. */ #define HAVE_ENDPROTOENT 1 /* Define to 1 if you have the `endservent' function. */ #define HAVE_ENDSERVENT 1 /* Define to 1 if you have the `ENGINE_load_cryptodev' function. */ #define HAVE_ENGINE_LOAD_CRYPTODEV 1 /* Define to 1 if you have the `EVP_sha256' function. */ #define HAVE_EVP_SHA256 1 /* Define to 1 if you have the `fcntl' function. */ #define HAVE_FCNTL 1 /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Whether getaddrinfo is available */ #define HAVE_GETADDRINFO 1 /* Define to 1 if you have the header file. */ #define HAVE_GETOPT_H 1 /* Define to 1 if you have the `gmtime_r' function. */ #define HAVE_GMTIME_R 1 /* If you have HMAC_CTX_init */ #define HAVE_HMAC_CTX_INIT 1 /* Define to 1 if you have the `inet_aton' function. */ #define HAVE_INET_ATON 1 /* Define to 1 if you have the `inet_ntop' function. */ #define HAVE_INET_NTOP 1 /* Define to 1 if you have the `inet_pton' function. */ #define HAVE_INET_PTON 1 /* define if you have inttypes.h */ #define HAVE_INTTYPES_H 1 /* if the function 'ioctlsocket' is available */ /* #undef HAVE_IOCTLSOCKET */ /* Define to 1 if you have the `isascii' function. */ #define HAVE_ISASCII 1 /* Define to 1 if you have the `isblank' function. */ #define HAVE_ISBLANK 1 /* Define to 1 if you have the `pcap' library (-lpcap). */ /* #undef HAVE_LIBPCAP */ /* Define to 1 if you have the `localtime_r' function. */ #define HAVE_LOCALTIME_R 1 /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #define HAVE_MALLOC 1 /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `memset' function. */ #define HAVE_MEMSET 1 /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IF_ETHER_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IGMP_H */ /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IN_SYSTM_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IP6_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IP_COMPAT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_UDP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NET_ETHERNET_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NET_IF_H */ /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_ERR_H 1 /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_RAND_H 1 /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_SSL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_PCAP_H */ /* Define to 1 if you have the `random' function. */ #define HAVE_RANDOM 1 /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #define HAVE_REALLOC 1 /* Define to 1 if you have the `sleep' function. */ #define HAVE_SLEEP 1 /* Define to 1 if you have the `snprintf' function. */ #define HAVE_SNPRINTF 1 /* Define if you have the SSL libraries installed. */ #define HAVE_SSL /**/ /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 /* Define to 1 if stdbool.h conforms to C99. */ #define HAVE_STDBOOL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strlcpy' function. */ #ifdef HAS_STRLCPY #define HAVE_STRLCPY 1 #else #undef HAVE_STRLCPY #endif /* Define to 1 if you have the `strtoul' function. */ #define HAVE_STRTOUL 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_MOUNT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* define if you have sys/socket.h */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* define if you have sys/types.h */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the `timegm' function. */ #define HAVE_TIMEGM 1 /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* define if you have unistd.h */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the `vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_WINSOCK2_H */ /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_WS2TCPIP_H */ /* Define to 1 if the system has the type `_Bool'. */ #define HAVE__BOOL 1 /* Is a CAFILE given at configure time */ /* #undef LDNS_DANE_CA_FILE */ /* Is a CAPATH given at configure time */ /* #undef LDNS_DANE_CA_PATH */ /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "libdns@nlnetlabs.nl" /* Define to the full name of this package. */ #define PACKAGE_NAME "ldns" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "ldns 1.6.17" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libdns" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "1.6.17" /* Define this to enable RR type NINFO. */ /* #undef RRTYPE_NINFO */ /* Define this to enable RR type OPENPGPKEY. */ /* #undef RRTYPE_OPENPGPKEY */ /* Define this to enable RR type RKEY. */ /* #undef RRTYPE_RKEY */ /* Define this to enable RR type TA. */ /* #undef RRTYPE_TA */ /* Define this to enable RR type URI. */ /* #undef RRTYPE_URI */ /* The size of `time_t', as computed by sizeof. */ #define SIZEOF_TIME_T 8 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define this to enable messages to stderr. */ /* #undef STDERR_MSGS */ /* System configuration dir */ #define SYSCONFDIR sysconfdir /* Define this to enable DANE support. */ #define USE_DANE 1 /* Define this to enable ECDSA support. */ #define USE_ECDSA 1 /* Define this to enable GOST support. */ /* #define USE_GOST 1 */ /* Define this to enable SHA256 and SHA512 support. */ #define USE_SHA2 1 /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # define _ALL_SOURCE 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # define _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # define _TANDEM_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 #endif /* Whether the windows socket API is used */ /* #undef USE_WINSOCK */ /* the version of the windows API enabled */ #define WINVER 0x0502 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN /* # undef WORDS_BIGENDIAN */ # endif #endif /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Enable for compile on Minix */ /* #undef _NETBSD_SOURCE */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* in_addr_t */ /* #undef in_addr_t */ /* in_port_t */ /* #undef in_port_t */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif /* Define to `short' if does not define. */ /* #undef int16_t */ /* Define to `int' if does not define. */ /* #undef int32_t */ /* Define to `long long' if does not define. */ /* #undef int64_t */ /* Define to `char' if does not define. */ /* #undef int8_t */ /* Define to `size_t' if does not define. */ /* #undef intptr_t */ /* Define to rpl_malloc if the replacement function should be used. */ /* #undef malloc */ /* Define to `int' if does not define. */ /* #undef pid_t */ /* Define to rpl_realloc if the replacement function should be used. */ /* #undef realloc */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ /* Define to 'int' if not defined */ /* #undef socklen_t */ /* Fallback member name for socket family in struct sockaddr_storage */ /* #undef ss_family */ /* Define to `int' if does not define. */ /* #undef ssize_t */ /* Define to `unsigned short' if does not define. */ /* #undef uint16_t */ /* Define to `unsigned int' if does not define. */ /* #undef uint32_t */ /* Define to `unsigned long long' if does not define. */ /* #undef uint64_t */ /* Define to `unsigned char' if does not define. */ /* #undef uint8_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ #include #include #include #include #ifndef LITTLE_ENDIAN #define LITTLE_ENDIAN 1234 #endif #ifndef BIG_ENDIAN #define BIG_ENDIAN 4321 #endif #ifndef BYTE_ORDER #ifdef WORDS_BIGENDIAN #define BYTE_ORDER BIG_ENDIAN #else #define BYTE_ORDER LITTLE_ENDIAN #endif /* WORDS_BIGENDIAN */ #endif /* BYTE_ORDER */ #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_WINSOCK2_H #include #endif #ifdef HAVE_WS2TCPIP_H #include #endif /* detect if we need to cast to unsigned int for FD_SET to avoid warnings */ #ifdef HAVE_WINSOCK2_H #define FD_SET_T (u_int) #else #define FD_SET_T #endif #ifdef __cplusplus extern "C" { #endif int ldns_b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize); /** * calculates the size needed to store the result of b64_ntop */ /*@unused@*/ static inline size_t ldns_b64_ntop_calculate_size(size_t srcsize) { return ((((srcsize + 2) / 3) * 4) + 1); } int ldns_b64_pton(char const *src, uint8_t *target, size_t targsize); /** * calculates the size needed to store the result of ldns_b64_pton */ /*@unused@*/ static inline size_t ldns_b64_pton_calculate_size(size_t srcsize) { return (((((srcsize + 3) / 4) * 3)) + 1); } /** * Given in dnssec_zone.c, also used in dnssec_sign.c:w */ int ldns_dname_compare_v(const void *a, const void *b); #ifndef HAVE_SLEEP /* use windows sleep, in millisecs, instead */ #define sleep(x) Sleep((x)*1000) #endif #ifndef HAVE_RANDOM #define srandom(x) srand(x) #define random(x) rand(x) #endif #ifndef HAVE_TIMEGM #include time_t timegm (struct tm *tm); #endif /* !TIMEGM */ #ifndef HAVE_GMTIME_R struct tm *gmtime_r(const time_t *timep, struct tm *result); #endif #ifndef HAVE_LOCALTIME_R struct tm *localtime_r(const time_t *timep, struct tm *result); #endif #ifndef HAVE_ISBLANK int isblank(int c); #endif /* !HAVE_ISBLANK */ #ifndef HAVE_ISASCII int isascii(int c); #endif /* !HAVE_ISASCII */ #ifndef HAVE_SNPRINTF #include int snprintf (char *str, size_t count, const char *fmt, ...); int vsnprintf (char *str, size_t count, const char *fmt, va_list arg); #endif /* HAVE_SNPRINTF */ #ifndef HAVE_INET_PTON int inet_pton(int af, const char* src, void* dst); #endif /* HAVE_INET_PTON */ #ifndef HAVE_INET_NTOP const char *inet_ntop(int af, const void *src, char *dst, size_t size); #endif #ifndef HAVE_INET_ATON int inet_aton(const char *cp, struct in_addr *addr); #endif #ifndef HAVE_MEMMOVE void *memmove(void *dest, const void *src, size_t n); #endif #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); #endif #ifdef __cplusplus } #endif #ifndef HAVE_GETADDRINFO #include "compat/fake-rfc2553.h" #endif #ifndef HAVE_STRTOUL #define strtoul (unsigned long)strtol #endif Net-LDNS-0.75/include/ldns/dane.h000644 000770 000024 00000022675 12471046240 016773 0ustar00calledstaff000000 000000 /* * dane.h -- defines for the DNS-Based Authentication of Named Entities (DANE) * Transport Layer Security (TLS) Protocol: TLSA * * Copyright (c) 2012, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ /** * \file * * This module contains base functions for creating and verifying TLSA RR's * with PKIX certificates, certificate chains and validation stores. * (See RFC6394 and RFC6698). * * Since those functions heavily rely op cryptographic operations, * this module is dependent on openssl. */ #ifndef LDNS_DANE_H #define LDNS_DANE_H #if LDNS_BUILD_CONFIG_USE_DANE #include #include #include #if LDNS_BUILD_CONFIG_HAVE_SSL #include #include #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ #ifdef __cplusplus extern "C" { #endif /** * The different "Certificate usage" rdata field values for a TLSA RR. */ enum ldns_enum_tlsa_certificate_usage { /** CA constraint */ LDNS_TLSA_USAGE_PKIX_TA = 0, LDNS_TLSA_USAGE_CA_CONSTRAINT = 0, /** Sevice certificate constraint */ LDNS_TLSA_USAGE_PKIX_EE = 1, LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT = 1, /** Trust anchor assertion */ LDNS_TLSA_USAGE_DANE_TA = 2, LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION = 2, /** Domain issued certificate */ LDNS_TLSA_USAGE_DANE_EE = 3, LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE = 3, /** Reserved for Private Use */ LDNS_TLSA_USAGE_PRIVCERT = 255 }; typedef enum ldns_enum_tlsa_certificate_usage ldns_tlsa_certificate_usage; /** * The different "Selector" rdata field values for a TLSA RR. */ enum ldns_enum_tlsa_selector { /** * Full certificate: the Certificate binary structure * as defined in [RFC5280] */ LDNS_TLSA_SELECTOR_CERT = 0, LDNS_TLSA_SELECTOR_FULL_CERTIFICATE = 0, /** * SubjectPublicKeyInfo: DER-encoded binary structure * as defined in [RFC5280] */ LDNS_TLSA_SELECTOR_SPKI = 1, LDNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO = 1, /** Reserved for Private Use */ LDNS_TLSA_SELECTOR_PRIVSEL = 255 }; typedef enum ldns_enum_tlsa_selector ldns_tlsa_selector; /** * The different "Matching type" rdata field values for a TLSA RR. */ enum ldns_enum_tlsa_matching_type { /** Exact match on selected content */ LDNS_TLSA_MATCHING_TYPE_FULL = 0, LDNS_TLSA_MATCHING_TYPE_NO_HASH_USED = 0, /** SHA-256 hash of selected content [RFC6234] */ LDNS_TLSA_MATCHING_TYPE_SHA2_256 = 1, LDNS_TLSA_MATCHING_TYPE_SHA256 = 1, /** SHA-512 hash of selected content [RFC6234] */ LDNS_TLSA_MATCHING_TYPE_SHA2_512 = 2, LDNS_TLSA_MATCHING_TYPE_SHA512 = 2, /** Reserved for Private Use */ LDNS_TLSA_MATCHING_TYPE_PRIVMATCH = 255 }; typedef enum ldns_enum_tlsa_matching_type ldns_tlsa_matching_type; /** * Known transports to use with TLSA owner names. */ enum ldns_enum_dane_transport { /** TCP */ LDNS_DANE_TRANSPORT_TCP = 0, /** UDP */ LDNS_DANE_TRANSPORT_UDP = 1, /** SCTP */ LDNS_DANE_TRANSPORT_SCTP = 2 }; typedef enum ldns_enum_dane_transport ldns_dane_transport; /** * Creates a dname consisting of the given name, prefixed by the service port * and type of transport: _port._transport.name. * * \param[out] tlsa_owner The created dname. * \param[in] name The dname that should be prefixed. * \param[in] port The service port number for wich the name should be created. * \param[in] transport The transport for wich the name should be created. * \return LDNS_STATUS_OK on success or an error code otherwise. */ ldns_status ldns_dane_create_tlsa_owner(ldns_rdf** tlsa_owner, const ldns_rdf* name, uint16_t port, ldns_dane_transport transport); #if LDNS_BUILD_CONFIG_HAVE_SSL /** * Creates a LDNS_RDF_TYPE_HEX type rdf based on the binary data choosen by * the selector and encoded using matching_type. * * \param[out] rdf The created created rdf of type LDNS_RDF_TYPE_HEX. * \param[in] cert The certificate from which the data is selected * \param[in] selector The full certificate or the public key * \param[in] matching_type The full data or the SHA256 or SHA512 hash * of the selected data * \return LDNS_STATUS_OK on success or an error code otherwise. */ ldns_status ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert, ldns_tlsa_selector selector, ldns_tlsa_matching_type matching_type); /** * Selects the certificate from cert, extra_certs or the pkix_validation_store * based on the value of cert_usage and index. * * \param[out] selected_cert The selected cert. * \param[in] cert The certificate to validate (or not) * \param[in] extra_certs Intermediate certificates that might be necessary * during validation. May be NULL, except when the certificate * usage is "Trust Anchor Assertion" because the trust anchor has * to be provided.(otherwise choose a "Domain issued certificate!" * \param[in] pkix_validation_store Used when the certificate usage is * "CA constraint" or "Service Certificate Constraint" to * validate the certificate and, in case of "CA constraint", * select the CA. * When pkix_validation_store is NULL, validation is explicitely * turned off and the behaviour is then the same as for "Trust * anchor assertion" and "Domain issued certificate" respectively. * \param[in] cert_usage Which certificate to use and how to validate. * \param[in] index Used to select the trust anchor when certificate usage * is "Trust Anchor Assertion". 0 is the last certificate in the * validation chain. 1 the one but last, etc. When index is -1, * the last certificate is used that MUST be self-signed. * This can help to make sure that the intended (self signed) * trust anchor is actually present in extra_certs (which is a * DANE requirement). * * \return LDNS_STATUS_OK on success or an error code otherwise. */ ldns_status ldns_dane_select_certificate(X509** selected_cert, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* pkix_validation_store, ldns_tlsa_certificate_usage cert_usage, int index); /** * Creates a TLSA resource record from the certificate. * No PKIX validation is performed! The given certificate is used as data * regardless the value of certificate_usage. * * \param[out] tlsa The created TLSA resource record. * \param[in] certificate_usage The value for the Certificate Usage field * \param[in] selector The value for the Selector field * \param[in] matching_type The value for the Matching Type field * \param[in] cert The certificate which data will be represented * * \return LDNS_STATUS_OK on success or an error code otherwise. */ ldns_status ldns_dane_create_tlsa_rr(ldns_rr** tlsa, ldns_tlsa_certificate_usage certificate_usage, ldns_tlsa_selector selector, ldns_tlsa_matching_type matching_type, X509* cert); /** * Verify if the given TLSA resource record matches the given certificate. * Reporting on a TLSA rr mismatch (LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH) * is preferred over PKIX failure (LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE). * So when PKIX validation is required by the TLSA Certificate usage, * but the TLSA data does not match, LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH * is returned whether the PKIX validated or not. * * \param[in] tlsa_rr The resource record that specifies what and how to * match the certificate. With tlsa_rr == NULL, regular PKIX * validation is performed. * \param[in] cert The certificate to match (and validate) * \param[in] extra_certs Intermediate certificates that might be necessary * creating the validation chain. * \param[in] pkix_validation_store Used when the certificate usage is * "CA constraint" or "Service Certificate Constraint" to * validate the certificate. * * \return LDNS_STATUS_OK on success, * LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH on TLSA data mismatch, * LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE when TLSA matched, * but the PKIX validation failed, or other ldns_status errors. */ ldns_status ldns_dane_verify_rr(const ldns_rr* tlsa_rr, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* pkix_validation_store); /** * Verify if any of the given TLSA resource records matches the given * certificate. * * \param[in] tlsas The resource records that specify what and how to * match the certificate. One must match for this function * to succeed. With tlsas == NULL or the number of TLSA records * in tlsas == 0, regular PKIX validation is performed. * \param[in] cert The certificate to match (and validate) * \param[in] extra_certs Intermediate certificates that might be necessary * creating the validation chain. * \param[in] pkix_validation_store Used when the certificate usage is * "CA constraint" or "Service Certificate Constraint" to * validate the certificate. * * \return LDNS_STATUS_OK on success, * LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE when one of the TLSA's * matched but the PKIX validation failed, * LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH when none of the TLSA's matched, * or other ldns_status errors. */ ldns_status ldns_dane_verify(ldns_rr_list* tlsas, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* pkix_validation_store); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ #ifdef __cplusplus } #endif #endif /* LDNS_BUILD_CONFIG_USE_DANE */ #endif /* LDNS_DANE_H */ Net-LDNS-0.75/include/ldns/dname.h000644 000770 000024 00000014447 12471046240 017146 0ustar00calledstaff000000 000000 /* * dname.h * * dname definitions * * a Net::DNS like library for C * * (c) NLnet Labs, 2004-2006 * * See the file LICENSE for the license */ /** * \file dname.h * * dname contains function to read and manipulate domain names. * * Example domain names are "www.nlnetlabs.nl." and "." (the root) * * If a domain name ends with a dot ("."), it is called a Fully Qualified * Domain Name (FQDN). In certain places (for instance when reading a zone * file), an origin (which is just another domain name) non-FQDNs will be * placed after the current. For instance, if i have a zone file where the * origin has been set to "nl.", and my file contains the name * "www.nlnetlabs", it will result in "www.nlnetlabs.nl.". Internally, dnames are * always absolute (the dot is added when it is missing and there is no origin). * * An FQDN is also * known as an absolute domain name, therefore the function to check this is * called \ref ldns_dname_str_absolute * * Domain names are stored in \ref ldns_rdf structures, with the type * \ref LDNS_RDF_TYPE_DNAME * * This module is *NOT* about the RR type called DNAME. */ #ifndef LDNS_DNAME_H #define LDNS_DNAME_H #include #include #ifdef __cplusplus extern "C" { #endif #define LDNS_DNAME_NORMALIZE tolower /** * concatenates two dnames together * \param[in] rd1 the leftside * \param[in] rd2 the rightside * \return a new rdf with leftside/rightside */ ldns_rdf *ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2); /** * concatenates rd2 after rd1 (rd2 is copied, rd1 is modified) * \param[in] rd1 the leftside * \param[in] rd2 the rightside * \return LDNS_STATUS_OK on success */ ldns_status ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2); /** * Returns a clone of the given dname with the labels * reversed * \param[in] d the dname to reverse * \return clone of the dname with the labels reversed. */ ldns_rdf *ldns_dname_reverse(const ldns_rdf *d); /** * Clones the given dname from the nth label on * \param[in] d The dname to clone * \param[in] n the label nr to clone from, if this is 0, the complete * dname is cloned * \return A newly allocated *rdf structure, containing the cloned dname, * or NULL if either d was NULL, not a dname, or if n >= * label_count */ ldns_rdf * ldns_dname_clone_from(const ldns_rdf *d, uint16_t n); /** * chop one label off the left side of a dname. so * wwww.nlnetlabs.nl, becomes nlnetlabs.nl * This new name is a clone and must be freed with ldns_deep_free() * \param[in] d the dname to chop * \return the remaining dname */ ldns_rdf *ldns_dname_left_chop(const ldns_rdf *d); /** * count the number of labels inside a LDNS_RDF_DNAME type rdf. * \param[in] *r the rdf * \return the number of labels */ uint8_t ldns_dname_label_count(const ldns_rdf *r); /** * creates a new dname rdf from a string. * \param[in] str string to use * \return ldns_rdf* or NULL in case of an error */ ldns_rdf *ldns_dname_new_frm_str(const char *str); /** * Create a new dname rdf from a string * \param[in] s the size of the new dname * \param[in] *data pointer to the actual data * * \return ldns_rdf* */ ldns_rdf *ldns_dname_new(uint16_t s, void *data); /** * Create a new dname rdf from data (the data is copied) * \param[in] size the size of the data * \param[in] *data pointer to the actual data * * \return ldns_rdf* */ ldns_rdf *ldns_dname_new_frm_data(uint16_t size, const void *data); /** * Put a dname into canonical fmt - ie. lowercase it * \param[in] rdf the dname to lowercase * \return void */ void ldns_dname2canonical(const ldns_rdf *rdf); /** * test wether the name sub falls under parent (i.e. is a subdomain * of parent). This function will return false if the given dnames are * equal. * \param[in] sub the name to test * \param[in] parent the parent's name * \return true if sub falls under parent, otherwise false */ bool ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent); /** * Compares the two dname rdf's according to the algorithm for ordering * in RFC4034 Section 6. * \param[in] dname1 First dname rdf to compare * \param[in] dname2 Second dname rdf to compare * \return -1 if dname1 comes before dname2, 1 if dname1 comes after dname2, and 0 if they are equal. */ int ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2); int ldns_dname_compare_v(const void *, const void *); /** * Checks whether the dname matches the given wildcard * \param[in] dname The dname to check * \param[in] wildcard The wildcard to check with * \return 1 If the wildcard matches, OR if 'wildcard' is not a wildcard and * the names are *exactly* the same * 0 If the wildcard does not match, or if it is not a wildcard and * the names are not the same */ int ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard); /** * check if middle lays in the interval defined by prev and next * prev <= middle < next. This is usefull for nsec checking * \param[in] prev the previous dname * \param[in] middle the dname to check * \param[in] next the next dname * return 0 on error or unknown, -1 when middle is in the interval, +1 when not */ int ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle, const ldns_rdf *next); /** * Checks whether the given dname string is absolute (i.e. ends with a '.') * \param[in] *dname_str a string representing the dname * \return true or false */ bool ldns_dname_str_absolute(const char *dname_str); /** * Checks whether the given dname is absolute (i.e. ends with a '.') * \param[in] *dname a rdf representing the dname * \return true or false */ bool ldns_dname_absolute(const ldns_rdf *dname); /** * look inside the rdf and if it is an LDNS_RDF_TYPE_DNAME * try and retrieve a specific label. The labels are numbered * starting from 0 (left most). * \param[in] rdf the rdf to look in * \param[in] labelpos return the label with this number * \return a ldns_rdf* with the label as name or NULL on error */ ldns_rdf * ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos); /** * Check if dname is a wildcard, starts with *. * \param[in] dname: the rdf to look in * \return true if a wildcard, false if not. */ int ldns_dname_is_wildcard(const ldns_rdf* dname); #ifdef __cplusplus } #endif #endif /* LDNS_DNAME_H */ Net-LDNS-0.75/include/ldns/dnssec.h000644 000770 000024 00000041344 12471046240 017335 0ustar00calledstaff000000 000000 /* * dnssec.h -- defines for the Domain Name System (SEC) (DNSSEC) * * Copyright (c) 2005-2008, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * A bunch of defines that are used in the DNS */ /** * \file dnssec.h * * This module contains base functions for DNSSEC operations * (RFC4033 t/m RFC4035). * * Since those functions heavily rely op cryptographic operations, * this module is dependent on openssl. * */ #ifndef LDNS_DNSSEC_H #define LDNS_DNSSEC_H #include #if LDNS_BUILD_CONFIG_HAVE_SSL #include #include #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define LDNS_MAX_KEYLEN 2048 #define LDNS_DNSSEC_KEYPROTO 3 /* default time before sigs expire */ #define LDNS_DEFAULT_EXP_TIME 2419200 /* 4 weeks */ /** return values for the old-signature callback */ #define LDNS_SIGNATURE_LEAVE_ADD_NEW 0 #define LDNS_SIGNATURE_LEAVE_NO_ADD 1 #define LDNS_SIGNATURE_REMOVE_ADD_NEW 2 #define LDNS_SIGNATURE_REMOVE_NO_ADD 3 /** * Returns the first RRSIG rr that corresponds to the rrset * with the given name and type * * \param[in] name The dname of the RRset covered by the RRSIG to find * \param[in] type The type of the RRset covered by the RRSIG to find * \param[in] rrs List of rrs to search in * \returns Pointer to the first RRsig ldns_rr found, or NULL if it is * not present */ ldns_rr *ldns_dnssec_get_rrsig_for_name_and_type(const ldns_rdf *name, const ldns_rr_type type, const ldns_rr_list *rrs); /** * Returns the DNSKEY that corresponds to the given RRSIG rr from the list, if * any * * \param[in] rrsig The rrsig to find the DNSKEY for * \param[in] rrs The rr list to find the key in * \return The DNSKEY that corresponds to the given RRSIG, or NULL if it was * not found. */ ldns_rr *ldns_dnssec_get_dnskey_for_rrsig(const ldns_rr *rrsig, const ldns_rr_list *rrs); /** * Returns the rdata field that contains the bitmap of the covered types of * the given NSEC record * * \param[in] nsec The nsec to get the covered type bitmap of * \return An ldns_rdf containing the bitmap, or NULL on error */ ldns_rdf *ldns_nsec_get_bitmap(ldns_rr *nsec); #define LDNS_NSEC3_MAX_ITERATIONS 65535 /** * Returns the dname of the closest (provable) encloser */ ldns_rdf * ldns_dnssec_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s); /** * Checks whether the packet contains rrsigs */ bool ldns_dnssec_pkt_has_rrsigs(const ldns_pkt *pkt); /** * Returns a ldns_rr_list containing the signatures covering the given name * and type */ ldns_rr_list *ldns_dnssec_pkt_get_rrsigs_for_name_and_type(const ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type); /** * Returns a ldns_rr_list containing the signatures covering the given type */ ldns_rr_list *ldns_dnssec_pkt_get_rrsigs_for_type(const ldns_pkt *pkt, ldns_rr_type type); /** * calculates a keytag of a key for use in DNSSEC. * * \param[in] key the key as an RR to use for the calc. * \return the keytag */ uint16_t ldns_calc_keytag(const ldns_rr *key); /** * Calculates keytag of DNSSEC key, operates on wireformat rdata. * \param[in] key the key as uncompressed wireformat rdata. * \param[in] keysize length of key data. * \return the keytag */ uint16_t ldns_calc_keytag_raw(uint8_t* key, size_t keysize); #if LDNS_BUILD_CONFIG_HAVE_SSL /** * converts a buffer holding key material to a DSA key in openssl. * * \param[in] key the key to convert * \return a DSA * structure with the key material */ DSA *ldns_key_buf2dsa(ldns_buffer *key); /** * Like ldns_key_buf2dsa, but uses raw buffer. * \param[in] key the uncompressed wireformat of the key. * \param[in] len length of key data * \return a DSA * structure with the key material */ DSA *ldns_key_buf2dsa_raw(unsigned char* key, size_t len); /** * Utility function to calculate hash using generic EVP_MD pointer. * \param[in] data the data to hash. * \param[in] len length of data. * \param[out] dest the destination of the hash, must be large enough. * \param[in] md the message digest to use. * \return true if worked, false on failure. */ int ldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest, const EVP_MD* md); /** * Converts a holding buffer with key material to EVP PKEY in openssl. * Only available if ldns was compiled with GOST. * \param[in] key data to convert * \param[in] keylen length of the key data * \return the key or NULL on error. */ EVP_PKEY* ldns_gost2pkey_raw(unsigned char* key, size_t keylen); /** * Converts a holding buffer with key material to EVP PKEY in openssl. * Only available if ldns was compiled with ECDSA. * \param[in] key data to convert * \param[in] keylen length of the key data * \param[in] algo precise algorithm to initialize ECC group values. * \return the key or NULL on error. */ EVP_PKEY* ldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ #if LDNS_BUILD_CONFIG_HAVE_SSL /** * converts a buffer holding key material to a RSA key in openssl. * * \param[in] key the key to convert * \return a RSA * structure with the key material */ RSA *ldns_key_buf2rsa(ldns_buffer *key); /** * Like ldns_key_buf2rsa, but uses raw buffer. * \param[in] key the uncompressed wireformat of the key. * \param[in] len length of key data * \return a RSA * structure with the key material */ RSA *ldns_key_buf2rsa_raw(unsigned char* key, size_t len); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ /** * returns a new DS rr that represents the given key rr. * * \param[in] *key the key to convert * \param[in] h the hash to use LDNS_SHA1/LDNS_SHA256 * * \return ldns_rr* a new rr pointer to a DS */ ldns_rr *ldns_key_rr2ds(const ldns_rr *key, ldns_hash h); /** * Create the type bitmap for an NSEC(3) record */ ldns_rdf * ldns_dnssec_create_nsec_bitmap(ldns_rr_type rr_type_list[], size_t size, ldns_rr_type nsec_type); /** * returns whether a rrset of the given type is found in the rrsets. * * \param[in] rrsets the rrsets to be tested * \param[in] type the type to test for * \return int 1 if the type was found, 0 otherwise. */ int ldns_dnssec_rrsets_contains_type (ldns_dnssec_rrsets *rrsets, ldns_rr_type type); /** * Creates NSEC */ ldns_rr * ldns_dnssec_create_nsec(ldns_dnssec_name *from, ldns_dnssec_name *to, ldns_rr_type nsec_type); /** * Creates NSEC3 */ ldns_rr * ldns_dnssec_create_nsec3(ldns_dnssec_name *from, ldns_dnssec_name *to, ldns_rdf *zone_name, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt); /** * Create a NSEC record * \param[in] cur_owner the current owner which should be taken as the starting point * \param[in] next_owner the rrlist which the nsec rr should point to * \param[in] rrs all rrs from the zone, to find all RR types of cur_owner in * \return a ldns_rr with the nsec record in it */ ldns_rr * ldns_create_nsec(ldns_rdf *cur_owner, ldns_rdf *next_owner, ldns_rr_list *rrs); /** * Calculates the hashed name using the given parameters * \param[in] *name The owner name to calculate the hash for * \param[in] algorithm The hash algorithm to use * \param[in] iterations The number of hash iterations to use * \param[in] salt_length The length of the salt in bytes * \param[in] salt The salt to use * \return The hashed owner name rdf, without the domain name */ ldns_rdf *ldns_nsec3_hash_name(ldns_rdf *name, uint8_t algorithm, uint16_t iterations, uint8_t salt_length, uint8_t *salt); /** * Sets all the NSEC3 options. The rr to set them in must be initialized with _new() and * type LDNS_RR_TYPE_NSEC3 * \param[in] *rr The RR to set the values in * \param[in] algorithm The NSEC3 hash algorithm * \param[in] flags The flags field * \param[in] iterations The number of hash iterations * \param[in] salt_length The length of the salt in bytes * \param[in] salt The salt bytes */ void ldns_nsec3_add_param_rdfs(ldns_rr *rr, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt); /* this will NOT return the NSEC3 completed, you will have to run the finalize function on the rrlist later! */ ldns_rr * ldns_create_nsec3(ldns_rdf *cur_owner, ldns_rdf *cur_zone, ldns_rr_list *rrs, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt, bool emptynonterminal); /** * Returns the hash algorithm used in the given NSEC3 RR * \param[in] *nsec3_rr The RR to read from * \return The algorithm identifier, or 0 on error */ uint8_t ldns_nsec3_algorithm(const ldns_rr *nsec3_rr); /** * Returns flags field */ uint8_t ldns_nsec3_flags(const ldns_rr *nsec3_rr); /** * Returns true if the opt-out flag has been set in the given NSEC3 RR * \param[in] *nsec3_rr The RR to read from * \return true if the RR has type NSEC3 and the opt-out bit has been set, false otherwise */ bool ldns_nsec3_optout(const ldns_rr *nsec3_rr); /** * Returns the number of hash iterations used in the given NSEC3 RR * \param[in] *nsec3_rr The RR to read from * \return The number of iterations */ uint16_t ldns_nsec3_iterations(const ldns_rr *nsec3_rr); /** * Returns the salt used in the given NSEC3 RR * \param[in] *nsec3_rr The RR to read from * \return The salt rdf, or NULL on error */ ldns_rdf *ldns_nsec3_salt(const ldns_rr *nsec3_rr); /** * Returns the length of the salt used in the given NSEC3 RR * \param[in] *nsec3_rr The RR to read from * \return The length of the salt in bytes */ uint8_t ldns_nsec3_salt_length(const ldns_rr *nsec3_rr); /** * Returns the salt bytes used in the given NSEC3 RR * \param[in] *nsec3_rr The RR to read from * \return The salt in bytes, this is alloced, so you need to free it */ uint8_t *ldns_nsec3_salt_data(const ldns_rr *nsec3_rr); /** * Returns the first label of the next ownername in the NSEC3 chain (ie. without the domain) * \param[in] nsec3_rr The RR to read from * \return The first label of the next owner name in the NSEC3 chain, or NULL on error */ ldns_rdf *ldns_nsec3_next_owner(const ldns_rr *nsec3_rr); /** * Returns the bitmap specifying the covered types of the given NSEC3 RR * \param[in] *nsec3_rr The RR to read from * \return The covered type bitmap rdf */ ldns_rdf *ldns_nsec3_bitmap(const ldns_rr *nsec3_rr); /** * Calculates the hashed name using the parameters of the given NSEC3 RR * \param[in] *nsec The RR to use the parameters from * \param[in] *name The owner name to calculate the hash for * \return The hashed owner name rdf, without the domain name */ ldns_rdf *ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, ldns_rdf *name); /** * Check if RR type t is enumerated and set in the RR type bitmap rdf. * \param[in] bitmap the RR type bitmap rdf to look in * \param[in] type the type to check for * \return true when t is found and set, otherwise return false */ bool ldns_nsec_bitmap_covers_type(const ldns_rdf* bitmap, ldns_rr_type type); /** * Checks if RR type t is enumerated in the type bitmap rdf and sets the bit. * \param[in] bitmap the RR type bitmap rdf to look in * \param[in] type the type to for which the bit to set * \return LDNS_STATUS_OK on success. LDNS_STATUS_TYPE_NOT_IN_BITMAP is * returned when the bitmap does not contain the bit to set. */ ldns_status ldns_nsec_bitmap_set_type(ldns_rdf* bitmap, ldns_rr_type type); /** * Checks if RR type t is enumerated in the type bitmap rdf and clears the bit. * \param[in] bitmap the RR type bitmap rdf to look in * \param[in] type the type to for which the bit to clear * \return LDNS_STATUS_OK on success. LDNS_STATUS_TYPE_NOT_IN_BITMAP is * returned when the bitmap does not contain the bit to clear. */ ldns_status ldns_nsec_bitmap_clear_type(ldns_rdf* bitmap, ldns_rr_type type); /** * Checks coverage of NSEC(3) RR name span * Remember that nsec and name must both be in canonical form (ie use * \ref ldns_rr2canonical and \ref ldns_dname2canonical prior to calling this * function) * * \param[in] nsec The NSEC RR to check * \param[in] name The owner dname to check, if the nsec record is a NSEC3 record, this should be the hashed name * \return true if the NSEC RR covers the owner name */ bool ldns_nsec_covers_name(const ldns_rr *nsec, const ldns_rdf *name); #if LDNS_BUILD_CONFIG_HAVE_SSL /** * verify a packet * \param[in] p the packet * \param[in] t the rr set type to check * \param[in] o the rr set name to check * \param[in] k list of keys * \param[in] s list of sigs (may be null) * \param[out] good_keys keys which validated the packet * \return status * */ ldns_status ldns_pkt_verify(ldns_pkt *p, ldns_rr_type t, ldns_rdf *o, ldns_rr_list *k, ldns_rr_list *s, ldns_rr_list *good_keys); /** * verify a packet * \param[in] p the packet * \param[in] t the rr set type to check * \param[in] o the rr set name to check * \param[in] k list of keys * \param[in] s list of sigs (may be null) * \param[in] check_time the time for which the validation is performed * \param[out] good_keys keys which validated the packet * \return status * */ ldns_status ldns_pkt_verify_time(ldns_pkt *p, ldns_rr_type t, ldns_rdf *o, ldns_rr_list *k, ldns_rr_list *s, time_t check_time, ldns_rr_list *good_keys); #endif /** * chains nsec3 list */ ldns_status ldns_dnssec_chain_nsec3_list(ldns_rr_list *nsec3_rrs); /** * compare for nsec3 sort */ int qsort_rr_compare_nsec3(const void *a, const void *b); /** * sort nsec3 list */ void ldns_rr_list_sort_nsec3(ldns_rr_list *unsorted); /** * Default callback function to always leave present signatures, and * add new ones * \param[in] sig The signature to check for removal (unused) * \param[in] n Optional argument (unused) * \return LDNS_SIGNATURE_LEAVE_ADD_NEW */ int ldns_dnssec_default_add_to_signatures(ldns_rr *sig, void *n); /** * Default callback function to always leave present signatures, and * add no new ones for the keys of these signatures * \param[in] sig The signature to check for removal (unused) * \param[in] n Optional argument (unused) * \return LDNS_SIGNATURE_LEAVE_NO_ADD */ int ldns_dnssec_default_leave_signatures(ldns_rr *sig, void *n); /** * Default callback function to always remove present signatures, but * add no new ones * \param[in] sig The signature to check for removal (unused) * \param[in] n Optional argument (unused) * \return LDNS_SIGNATURE_REMOVE_NO_ADD */ int ldns_dnssec_default_delete_signatures(ldns_rr *sig, void *n); /** * Default callback function to always leave present signatures, and * add new ones * \param[in] sig The signature to check for removal (unused) * \param[in] n Optional argument (unused) * \return LDNS_SIGNATURE_REMOVE_ADD_NEW */ int ldns_dnssec_default_replace_signatures(ldns_rr *sig, void *n); #if LDNS_BUILD_CONFIG_HAVE_SSL /** * Converts the DSA signature from ASN1 representation (RFC2459, as * used by OpenSSL) to raw signature data as used in DNS (rfc2536) * * \param[in] sig The signature in RFC2459 format * \param[in] sig_len The length of the signature * \return a new rdf with the signature */ ldns_rdf * ldns_convert_dsa_rrsig_asn12rdf(const ldns_buffer *sig, const long sig_len); /** * Converts the RRSIG signature RDF (in rfc2536 format) to a buffer * with the signature in rfc2459 format * * \param[out] target_buffer buffer to place the signature data * \param[in] sig_rdf The signature rdf to convert * \return LDNS_STATUS_OK on success, error code otherwise */ ldns_status ldns_convert_dsa_rrsig_rdf2asn1(ldns_buffer *target_buffer, const ldns_rdf *sig_rdf); /** * Converts the ECDSA signature from ASN1 representation (as * used by OpenSSL) to raw signature data as used in DNS * This routine is only present if ldns is compiled with ecdsa support. * * \param[in] sig The signature in ASN1 format * \param[in] sig_len The length of the signature * \return a new rdf with the signature */ ldns_rdf * ldns_convert_ecdsa_rrsig_asn12rdf(const ldns_buffer *sig, const long sig_len); /** * Converts the RRSIG signature RDF (from DNS) to a buffer with the * signature in ASN1 format as openssl uses it. * This routine is only present if ldns is compiled with ecdsa support. * * \param[out] target_buffer buffer to place the signature data in ASN1. * \param[in] sig_rdf The signature rdf to convert * \return LDNS_STATUS_OK on success, error code otherwise */ ldns_status ldns_convert_ecdsa_rrsig_rdf2asn1(ldns_buffer *target_buffer, const ldns_rdf *sig_rdf); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ #ifdef __cplusplus } #endif #endif /* LDNS_DNSSEC_H */ Net-LDNS-0.75/include/ldns/dnssec_sign.h000644 000770 000024 00000034140 12471046240 020351 0ustar00calledstaff000000 000000 /** dnssec_verify */ #ifndef LDNS_DNSSEC_SIGN_H #define LDNS_DNSSEC_SIGN_H #include #ifdef __cplusplus extern "C" { #endif /* sign functions */ /** Sign flag that makes DNSKEY type signed by all keys, not only by SEP keys*/ #define LDNS_SIGN_DNSKEY_WITH_ZSK 1 /** * Create an empty RRSIG RR (i.e. without the actual signature data) * \param[in] rrset The RRset to create the signature for * \param[in] key The key that will create the signature * \return signature rr */ ldns_rr * ldns_create_empty_rrsig(ldns_rr_list *rrset, ldns_key *key); /** * Sign the buffer which contains the wiredata of an rrset, and the * corresponding empty rrsig rr with the given key * \param[in] sign_buf the buffer with data to sign * \param[in] key the key to sign with * \return an rdata field with the signature data */ ldns_rdf * ldns_sign_public_buffer(ldns_buffer *sign_buf, ldns_key *key); /** * Sign an rrset * \param[in] rrset the rrset * \param[in] keys the keys to use * \return a rr_list with the signatures */ ldns_rr_list *ldns_sign_public(ldns_rr_list *rrset, ldns_key_list *keys); #if LDNS_BUILD_CONFIG_HAVE_SSL /** * Sign a buffer with the DSA key (hash with SHA1) * \param[in] to_sign buffer with the data * \param[in] key the key to use * \return a ldns_rdf with the signed data */ ldns_rdf *ldns_sign_public_dsa(ldns_buffer *to_sign, DSA *key); /** * Sign data with EVP (general method for different algorithms) * * \param[in] to_sign The ldns_buffer containing raw data that is * to be signed * \param[in] key The EVP_PKEY key structure to sign with * \param[in] digest_type The digest algorithm to use in the creation of * the signature * \return ldns_rdf for the RRSIG ldns_rr */ ldns_rdf *ldns_sign_public_evp(ldns_buffer *to_sign, EVP_PKEY *key, const EVP_MD *digest_type); /** * Sign a buffer with the RSA key (hash with SHA1) * \param[in] to_sign buffer with the data * \param[in] key the key to use * \return a ldns_rdf with the signed data */ ldns_rdf *ldns_sign_public_rsasha1(ldns_buffer *to_sign, RSA *key); /** * Sign a buffer with the RSA key (hash with MD5) * \param[in] to_sign buffer with the data * \param[in] key the key to use * \return a ldns_rdf with the signed data */ ldns_rdf *ldns_sign_public_rsamd5(ldns_buffer *to_sign, RSA *key); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ /** * Marks the names in the zone that are occluded. Those names will be skipped * when walking the tree with the ldns_dnssec_name_node_next_nonglue() * function. But watch out! Names that are partially occluded (like glue with * the same name as the delegation) will not be marked and should specifically * be taken into account separately. * * When glue_list is given (not NULL), in the process of marking the names, all * glue resource records will be pushed to that list, even glue at the delegation name. * * \param[in] zone the zone in which to mark the names * \param[in] glue_list the list to which to push the glue rrs * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_mark_and_get_glue( ldns_dnssec_zone *zone, ldns_rr_list *glue_list); /** * Marks the names in the zone that are occluded. Those names will be skipped * when walking the tree with the ldns_dnssec_name_node_next_nonglue() * function. But watch out! Names that are partially occluded (like glue with * the same name as the delegation) will not be marked and should specifically * be taken into account separately. * * \param[in] zone the zone in which to mark the names * \return LDNS_STATUS_OK on succesful completion */ ldns_status ldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone); /** * Finds the first dnssec_name node in the rbtree that is not occluded. * It *does* return names that are partially occluded. * * \param[in] node the first node to check * \return the first node that has not been marked as glue, or NULL * if not found (TODO: make that LDNS_RBTREE_NULL?) */ ldns_rbnode_t *ldns_dnssec_name_node_next_nonglue(ldns_rbnode_t *node); /** * Adds NSEC records to the given dnssec_zone * * \param[in] zone the zone to add the records to * \param[in] new_rrs ldns_rr's created by this function are * added to this rr list, so the caller can free them later * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs); /** * Adds NSEC3 records to the zone */ ldns_status ldns_dnssec_zone_create_nsec3s(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt); /** * remove signatures if callback function tells to * * \param[in] signatures list of signatures to check, and * possibly remove, depending on the value of the * callback * \param[in] key_list these are marked to be used or not, * on the return value of the callback * \param[in] func this function is called to specify what to * do with each signature (and corresponding key) * \param[in] arg Optional argument for the callback function * \returns pointer to the new signatures rrs (the original * passed to this function may have been removed) */ ldns_dnssec_rrs *ldns_dnssec_remove_signatures(ldns_dnssec_rrs *signatures, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg); /** * Adds signatures to the zone * * \param[in] zone the zone to add RRSIG Resource Records to * \param[in] new_rrs the RRSIG RRs that are created are also * added to this list, so the caller can free them * later * \param[in] key_list list of keys to sign with. * \param[in] func Callback function to decide what keys to * use and what to do with old signatures * \param[in] arg Optional argument for the callback function * \param[in] flags option flags for signing process. 0 makes DNSKEY * RRset signed with the minimal key set, that is only SEP keys are used * for signing. If there are no SEP keys available, non-SEP keys will * be used. LDNS_SIGN_DNSKEY_WITH_ZSK makes DNSKEY type signed with all * keys. 0 is the default. * \return LDNS_STATUS_OK on success, error otherwise */ ldns_status ldns_dnssec_zone_create_rrsigs_flg(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void*), void *arg, int flags); /** * Adds signatures to the zone * * \param[in] zone the zone to add RRSIG Resource Records to * \param[in] new_rrs the RRSIG RRs that are created are also * added to this list, so the caller can free them * later * \param[in] key_list list of keys to sign with. * \param[in] func Callback function to decide what keys to * use and what to do with old signatures * \param[in] arg Optional argument for the callback function * \return LDNS_STATUS_OK on success, error otherwise */ ldns_status ldns_dnssec_zone_create_rrsigs(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void*), void *arg); /** * signs the given zone with the given keys * * \param[in] zone the zone to sign * \param[in] key_list the list of keys to sign the zone with * \param[in] new_rrs newly created resource records are added to this list, to free them later * \param[in] func callback function that decides what to do with old signatures * This function takes an ldns_rr* and an optional void *arg argument, and returns one of four values: * LDNS_SIGNATURE_LEAVE_ADD_NEW: * leave the signature and add a new one for the corresponding key * LDNS_SIGNATURE_REMOVE_ADD_NEW: * remove the signature and replace is with a new one from the same key * LDNS_SIGNATURE_LEAVE_NO_ADD: * leave the signature and do not add a new one with the corresponding key * LDNS_SIGNATURE_REMOVE_NO_ADD: * remove the signature and do not replace * * \param[in] arg optional argument for the callback function * \param[in] flags option flags for signing process. 0 makes DNSKEY * RRset signed with the minimal key set, that is only SEP keys are used * for signing. If there are no SEP keys available, non-SEP keys will * be used. LDNS_SIGN_DNSKEY_WITH_ZSK makes DNSKEY type signed with all * keys. 0 is the default. * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_sign_flg(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg, int flags); /** * signs the given zone with the given new zone, with NSEC3 * * \param[in] zone the zone to sign * \param[in] key_list the list of keys to sign the zone with * \param[in] new_rrs newly created resource records are added to this list, to free them later * \param[in] func callback function that decides what to do with old signatures * \param[in] arg optional argument for the callback function * \param[in] algorithm the NSEC3 hashing algorithm to use * \param[in] flags NSEC3 flags * \param[in] iterations the number of NSEC3 hash iterations to use * \param[in] salt_length the length (in octets) of the NSEC3 salt * \param[in] salt the NSEC3 salt data * \param[in] signflags option flags for signing process. 0 is the default. * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_sign_nsec3_flg(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt, int signflags); /** * signs the given zone with the given new zone, with NSEC3 * * \param[in] zone the zone to sign * \param[in] key_list the list of keys to sign the zone with * \param[in] new_rrs newly created resource records are added to this list, to free them later * \param[in] func callback function that decides what to do with old signatures * \param[in] arg optional argument for the callback function * \param[in] algorithm the NSEC3 hashing algorithm to use * \param[in] flags NSEC3 flags * \param[in] iterations the number of NSEC3 hash iterations to use * \param[in] salt_length the length (in octets) of the NSEC3 salt * \param[in] salt the NSEC3 salt data * \param[in] signflags option flags for signing process. 0 is the default. * \param[out] map a referenced rbtree pointer variable. The newly created * rbtree will contain mappings from hashed owner names to the * unhashed name. * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt, int signflags, ldns_rbtree_t **map ); /** * signs the given zone with the given keys * * \param[in] zone the zone to sign * \param[in] key_list the list of keys to sign the zone with * \param[in] new_rrs newly created resource records are added to this list, to free them later * \param[in] func callback function that decides what to do with old signatures * This function takes an ldns_rr* and an optional void *arg argument, and returns one of four values: * LDNS_SIGNATURE_LEAVE_ADD_NEW: * leave the signature and add a new one for the corresponding key * LDNS_SIGNATURE_REMOVE_ADD_NEW: * remove the signature and replace is with a new one from the same key * LDNS_SIGNATURE_LEAVE_NO_ADD: * leave the signature and do not add a new one with the corresponding key * LDNS_SIGNATURE_REMOVE_NO_ADD: * remove the signature and do not replace * * \param[in] arg optional argument for the callback function * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_sign(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg); /** * signs the given zone with the given new zone, with NSEC3 * * \param[in] zone the zone to sign * \param[in] key_list the list of keys to sign the zone with * \param[in] new_rrs newly created resource records are added to this list, to free them later * \param[in] func callback function that decides what to do with old signatures * \param[in] arg optional argument for the callback function * \param[in] algorithm the NSEC3 hashing algorithm to use * \param[in] flags NSEC3 flags * \param[in] iterations the number of NSEC3 hash iterations to use * \param[in] salt_length the length (in octets) of the NSEC3 salt * \param[in] salt the NSEC3 salt data * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_sign_nsec3(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void *), void *arg, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt); /** * Signs the zone, and returns a newly allocated signed zone * \param[in] zone the zone to sign * \param[in] key_list list of keys to sign with * \return signed zone */ ldns_zone *ldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list); /** * Signs the zone with NSEC3, and returns a newly allocated signed zone * \param[in] zone the zone to sign * \param[in] key_list list of keys to sign with * \param[in] algorithm the NSEC3 hashing algorithm to use * \param[in] flags NSEC3 flags * \param[in] iterations the number of NSEC3 hash iterations to use * \param[in] salt_length the length (in octets) of the NSEC3 salt * \param[in] salt the NSEC3 salt data * \return signed zone */ ldns_zone *ldns_zone_sign_nsec3(ldns_zone *zone, ldns_key_list *key_list, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt); #ifdef __cplusplus } #endif #endif Net-LDNS-0.75/include/ldns/dnssec_verify.h000644 000770 000024 00000072556 12471046240 020732 0ustar00calledstaff000000 000000 /** dnssec_verify */ #ifndef LDNS_DNSSEC_VERIFY_H #define LDNS_DNSSEC_VERIFY_H #define LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS 10 #include #include #ifdef __cplusplus extern "C" { #endif /** * Chain structure that contains all DNSSEC data needed to * verify an rrset */ typedef struct ldns_dnssec_data_chain_struct ldns_dnssec_data_chain; struct ldns_dnssec_data_chain_struct { ldns_rr_list *rrset; ldns_rr_list *signatures; ldns_rr_type parent_type; ldns_dnssec_data_chain *parent; ldns_pkt_rcode packet_rcode; ldns_rr_type packet_qtype; bool packet_nodata; }; /** * Creates a new dnssec_chain structure * \return ldns_dnssec_data_chain * */ ldns_dnssec_data_chain *ldns_dnssec_data_chain_new(void); /** * Frees a dnssec_data_chain structure * * \param[in] *chain The chain to free */ void ldns_dnssec_data_chain_free(ldns_dnssec_data_chain *chain); /** * Frees a dnssec_data_chain structure, and all data * contained therein * * \param[in] *chain The dnssec_data_chain to free */ void ldns_dnssec_data_chain_deep_free(ldns_dnssec_data_chain *chain); /** * Prints the dnssec_data_chain to the given file stream * * \param[in] *out The file stream to print to * \param[in] *chain The dnssec_data_chain to print */ void ldns_dnssec_data_chain_print(FILE *out, const ldns_dnssec_data_chain *chain); /** * Prints the dnssec_data_chain to the given file stream * * \param[in] *out The file stream to print to * \param[in] *fmt The format of the textual representation * \param[in] *chain The dnssec_data_chain to print */ void ldns_dnssec_data_chain_print_fmt(FILE *out, const ldns_output_format *fmt, const ldns_dnssec_data_chain *chain); /** * Build an ldns_dnssec_data_chain, which contains all * DNSSEC data that is needed to derive the trust tree later * * The data_set will be cloned * * \param[in] *res resolver structure for further needed queries * \param[in] qflags resolution flags * \param[in] *data_set The original rrset where the chain ends * \param[in] *pkt optional, can contain the original packet * (and hence the sigs and maybe the key) * \param[in] *orig_rr The original Resource Record * * \return the DNSSEC data chain */ ldns_dnssec_data_chain *ldns_dnssec_build_data_chain(ldns_resolver *res, const uint16_t qflags, const ldns_rr_list *data_set, const ldns_pkt *pkt, ldns_rr *orig_rr); /** * Tree structure that contains the relation of DNSSEC data, * and their cryptographic status. * * This tree is derived from a data_chain, and can be used * to look whether there is a connection between an RRSET * and a trusted key. The tree only contains pointers to the * data_chain, and therefore one should *never* free() the * data_chain when there is still a trust tree derived from * that chain. * * Example tree: * key key key * \ | / * \ | / * \ | / * ds * | * key * | * key * | * rr * * For each signature there is a parent; if the parent * pointer is null, it couldn't be found and there was no * denial; otherwise is a tree which contains either a * DNSKEY, a DS, or a NSEC rr */ typedef struct ldns_dnssec_trust_tree_struct ldns_dnssec_trust_tree; struct ldns_dnssec_trust_tree_struct { ldns_rr *rr; /* the complete rrset this rr was in */ ldns_rr_list *rrset; ldns_dnssec_trust_tree *parents[LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS]; ldns_status parent_status[LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS]; /** for debugging, add signatures too (you might want those if they contain errors) */ ldns_rr *parent_signature[LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS]; size_t parent_count; }; /** * Creates a new (empty) dnssec_trust_tree structure * * \return ldns_dnssec_trust_tree * */ ldns_dnssec_trust_tree *ldns_dnssec_trust_tree_new(void); /** * Frees the dnssec_trust_tree recursively * * There is no deep free; all data in the trust tree * consists of pointers to a data_chain * * \param[in] tree The tree to free */ void ldns_dnssec_trust_tree_free(ldns_dnssec_trust_tree *tree); /** * returns the depth of the trust tree * * \param[in] tree tree to calculate the depth of * \return The depth of the tree */ size_t ldns_dnssec_trust_tree_depth(ldns_dnssec_trust_tree *tree); /** * Prints the dnssec_trust_tree structure to the given file * stream. * * If a link status is not LDNS_STATUS_OK; the status and * relevant signatures are printed too * * \param[in] *out The file stream to print to * \param[in] tree The trust tree to print * \param[in] tabs Prepend each line with tabs*2 spaces * \param[in] extended If true, add little explanation lines to the output */ void ldns_dnssec_trust_tree_print(FILE *out, ldns_dnssec_trust_tree *tree, size_t tabs, bool extended); /** * Prints the dnssec_trust_tree structure to the given file * stream. * * If a link status is not LDNS_STATUS_OK; the status and * relevant signatures are printed too * * \param[in] *out The file stream to print to * \param[in] *fmt The format of the textual representation * \param[in] tree The trust tree to print * \param[in] tabs Prepend each line with tabs*2 spaces * \param[in] extended If true, add little explanation lines to the output */ void ldns_dnssec_trust_tree_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_trust_tree *tree, size_t tabs, bool extended); /** * Adds a trust tree as a parent for the given trust tree * * \param[in] *tree The tree to add the parent to * \param[in] *parent The parent tree to add * \param[in] *parent_signature The RRSIG relevant to this parent/child * connection * \param[in] parent_status The DNSSEC status for this parent, child and RRSIG * \return LDNS_STATUS_OK if the addition succeeds, error otherwise */ ldns_status ldns_dnssec_trust_tree_add_parent(ldns_dnssec_trust_tree *tree, const ldns_dnssec_trust_tree *parent, const ldns_rr *parent_signature, const ldns_status parent_status); /** * Generates a dnssec_trust_tree for the given rr from the * given data_chain * * This does not clone the actual data; Don't free the * data_chain before you are done with this tree * * \param[in] *data_chain The chain to derive the trust tree from * \param[in] *rr The RR this tree will be about * \return ldns_dnssec_trust_tree * */ ldns_dnssec_trust_tree *ldns_dnssec_derive_trust_tree( ldns_dnssec_data_chain *data_chain, ldns_rr *rr); /** * Generates a dnssec_trust_tree for the given rr from the * given data_chain * * This does not clone the actual data; Don't free the * data_chain before you are done with this tree * * \param[in] *data_chain The chain to derive the trust tree from * \param[in] *rr The RR this tree will be about * \param[in] check_time the time for which the validation is performed * \return ldns_dnssec_trust_tree * */ ldns_dnssec_trust_tree *ldns_dnssec_derive_trust_tree_time( ldns_dnssec_data_chain *data_chain, ldns_rr *rr, time_t check_time); /** * Sub function for derive_trust_tree that is used for a 'normal' rrset * * \param[in] new_tree The trust tree that we are building * \param[in] data_chain The data chain containing the data for the trust tree * \param[in] cur_sig_rr The currently relevant signature */ void ldns_dnssec_derive_trust_tree_normal_rrset( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_sig_rr); /** * Sub function for derive_trust_tree that is used for a 'normal' rrset * * \param[in] new_tree The trust tree that we are building * \param[in] data_chain The data chain containing the data for the trust tree * \param[in] cur_sig_rr The currently relevant signature * \param[in] check_time the time for which the validation is performed */ void ldns_dnssec_derive_trust_tree_normal_rrset_time( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_sig_rr, time_t check_time); /** * Sub function for derive_trust_tree that is used for DNSKEY rrsets * * \param[in] new_tree The trust tree that we are building * \param[in] data_chain The data chain containing the data for the trust tree * \param[in] cur_rr The currently relevant DNSKEY RR * \param[in] cur_sig_rr The currently relevant signature */ void ldns_dnssec_derive_trust_tree_dnskey_rrset( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_rr, ldns_rr *cur_sig_rr); /** * Sub function for derive_trust_tree that is used for DNSKEY rrsets * * \param[in] new_tree The trust tree that we are building * \param[in] data_chain The data chain containing the data for the trust tree * \param[in] cur_rr The currently relevant DNSKEY RR * \param[in] cur_sig_rr The currently relevant signature * \param[in] check_time the time for which the validation is performed */ void ldns_dnssec_derive_trust_tree_dnskey_rrset_time( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_rr, ldns_rr *cur_sig_rr, time_t check_time); /** * Sub function for derive_trust_tree that is used for DS rrsets * * \param[in] new_tree The trust tree that we are building * \param[in] data_chain The data chain containing the data for the trust tree * \param[in] cur_rr The currently relevant DS RR */ void ldns_dnssec_derive_trust_tree_ds_rrset( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_rr); /** * Sub function for derive_trust_tree that is used for DS rrsets * * \param[in] new_tree The trust tree that we are building * \param[in] data_chain The data chain containing the data for the trust tree * \param[in] cur_rr The currently relevant DS RR * \param[in] check_time the time for which the validation is performed */ void ldns_dnssec_derive_trust_tree_ds_rrset_time( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, ldns_rr *cur_rr, time_t check_time); /** * Sub function for derive_trust_tree that is used when there are no * signatures * * \param[in] new_tree The trust tree that we are building * \param[in] data_chain The data chain containing the data for the trust tree */ void ldns_dnssec_derive_trust_tree_no_sig( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain); /** * Sub function for derive_trust_tree that is used when there are no * signatures * * \param[in] new_tree The trust tree that we are building * \param[in] data_chain The data chain containing the data for the trust tree * \param[in] check_time the time for which the validation is performed */ void ldns_dnssec_derive_trust_tree_no_sig_time( ldns_dnssec_trust_tree *new_tree, ldns_dnssec_data_chain *data_chain, time_t check_time); /** * Returns OK if there is a trusted path in the tree to one of * the DNSKEY or DS RRs in the given list * * \param *tree The trust tree so search * \param *keys A ldns_rr_list of DNSKEY and DS rrs to look for * * \return LDNS_STATUS_OK if there is a trusted path to one of * the keys, or the *first* error encountered * if there were no paths */ ldns_status ldns_dnssec_trust_tree_contains_keys( ldns_dnssec_trust_tree *tree, ldns_rr_list *keys); /** * Verifies a list of signatures for one rrset. * * \param[in] rrset the rrset to verify * \param[in] rrsig a list of signatures to check * \param[in] keys a list of keys to check with * \param[out] good_keys if this is a (initialized) list, the pointer to keys * from keys that validate one of the signatures * are added to it * \return status LDNS_STATUS_OK if there is at least one correct key */ ldns_status ldns_verify(ldns_rr_list *rrset, ldns_rr_list *rrsig, const ldns_rr_list *keys, ldns_rr_list *good_keys); /** * Verifies a list of signatures for one rrset. * * \param[in] rrset the rrset to verify * \param[in] rrsig a list of signatures to check * \param[in] keys a list of keys to check with * \param[in] check_time the time for which the validation is performed * \param[out] good_keys if this is a (initialized) list, the pointer to keys * from keys that validate one of the signatures * are added to it * \return status LDNS_STATUS_OK if there is at least one correct key */ ldns_status ldns_verify_time(ldns_rr_list *rrset, ldns_rr_list *rrsig, const ldns_rr_list *keys, time_t check_time, ldns_rr_list *good_keys); /** * Verifies a list of signatures for one rrset, but disregard the time. * Inception and Expiration are not checked. * * \param[in] rrset the rrset to verify * \param[in] rrsig a list of signatures to check * \param[in] keys a list of keys to check with * \param[out] good_keys if this is a (initialized) list, the pointer to keys * from keys that validate one of the signatures * are added to it * \return status LDNS_STATUS_OK if there is at least one correct key */ ldns_status ldns_verify_notime(ldns_rr_list *rrset, ldns_rr_list *rrsig, const ldns_rr_list *keys, ldns_rr_list *good_keys); /** * Tries to build an authentication chain from the given * keys down to the queried domain. * * If we find a valid trust path, return the valid keys for the domain. * * \param[in] res the current resolver * \param[in] domain the domain we want valid keys for * \param[in] keys the current set of trusted keys * \param[out] status pointer to the status variable where the result * code will be stored * \return the set of trusted keys for the domain, or NULL if no * trust path could be built. */ ldns_rr_list *ldns_fetch_valid_domain_keys(const ldns_resolver * res, const ldns_rdf * domain, const ldns_rr_list * keys, ldns_status *status); /** * Tries to build an authentication chain from the given * keys down to the queried domain. * * If we find a valid trust path, return the valid keys for the domain. * * \param[in] res the current resolver * \param[in] domain the domain we want valid keys for * \param[in] keys the current set of trusted keys * \param[in] check_time the time for which the validation is performed * \param[out] status pointer to the status variable where the result * code will be stored * \return the set of trusted keys for the domain, or NULL if no * trust path could be built. */ ldns_rr_list *ldns_fetch_valid_domain_keys_time(const ldns_resolver * res, const ldns_rdf * domain, const ldns_rr_list * keys, time_t check_time, ldns_status *status); /** * Validates the DNSKEY RRset for the given domain using the provided * trusted keys. * * \param[in] res the current resolver * \param[in] domain the domain we want valid keys for * \param[in] keys the current set of trusted keys * \return the set of trusted keys for the domain, or NULL if the RRSET * could not be validated */ ldns_rr_list *ldns_validate_domain_dnskey (const ldns_resolver *res, const ldns_rdf *domain, const ldns_rr_list *keys); /** * Validates the DNSKEY RRset for the given domain using the provided * trusted keys. * * \param[in] res the current resolver * \param[in] domain the domain we want valid keys for * \param[in] keys the current set of trusted keys * \param[in] check_time the time for which the validation is performed * \return the set of trusted keys for the domain, or NULL if the RRSET * could not be validated */ ldns_rr_list *ldns_validate_domain_dnskey_time( const ldns_resolver *res, const ldns_rdf *domain, const ldns_rr_list *keys, time_t check_time); /** * Validates the DS RRset for the given domain using the provided trusted keys. * * \param[in] res the current resolver * \param[in] domain the domain we want valid keys for * \param[in] keys the current set of trusted keys * \return the set of trusted keys for the domain, or NULL if the RRSET could not be validated */ ldns_rr_list *ldns_validate_domain_ds(const ldns_resolver *res, const ldns_rdf * domain, const ldns_rr_list * keys); /** * Validates the DS RRset for the given domain using the provided trusted keys. * * \param[in] res the current resolver * \param[in] domain the domain we want valid keys for * \param[in] keys the current set of trusted keys * \param[in] check_time the time for which the validation is performed * \return the set of trusted keys for the domain, or NULL if the RRSET could not be validated */ ldns_rr_list *ldns_validate_domain_ds_time( const ldns_resolver *res, const ldns_rdf *domain, const ldns_rr_list * keys, time_t check_time); /** * Verifies a list of signatures for one RRset using a valid trust path. * * \param[in] res the current resolver * \param[in] rrset the rrset to verify * \param[in] rrsigs a list of signatures to check * \param[out] validating_keys if this is a (initialized) list, the * keys from keys that validate one of * the signatures are added to it * \return status LDNS_STATUS_OK if there is at least one correct key */ ldns_status ldns_verify_trusted(ldns_resolver *res, ldns_rr_list *rrset, ldns_rr_list *rrsigs, ldns_rr_list *validating_keys); /** * Verifies a list of signatures for one RRset using a valid trust path. * * \param[in] res the current resolver * \param[in] rrset the rrset to verify * \param[in] rrsigs a list of signatures to check * \param[in] check_time the time for which the validation is performed * \param[out] validating_keys if this is a (initialized) list, the * keys from keys that validate one of * the signatures are added to it * \return status LDNS_STATUS_OK if there is at least one correct key */ ldns_status ldns_verify_trusted_time( ldns_resolver *res, ldns_rr_list *rrset, ldns_rr_list *rrsigs, time_t check_time, ldns_rr_list *validating_keys); /** * denial is not just a river in egypt * * \param[in] rr The (query) RR to check the denial of existence for * \param[in] nsecs The list of NSEC RRs that are supposed to deny the * existence of the RR * \param[in] rrsigs The RRSIG RR covering the NSEC RRs * \return LDNS_STATUS_OK if the NSEC RRs deny the existence, error code * containing the reason they do not otherwise */ ldns_status ldns_dnssec_verify_denial(ldns_rr *rr, ldns_rr_list *nsecs, ldns_rr_list *rrsigs); /** * Denial of existence using NSEC3 records * Since NSEC3 is a bit more complicated than normal denial, some * context arguments are needed * * \param[in] rr The (query) RR to check the denial of existence for * \param[in] nsecs The list of NSEC3 RRs that are supposed to deny the * existence of the RR * \param[in] rrsigs The RRSIG rr covering the NSEC RRs * \param[in] packet_rcode The RCODE value of the packet that provided the * NSEC3 RRs * \param[in] packet_qtype The original query RR type * \param[in] packet_nodata True if the providing packet had an empty ANSWER * section * \return LDNS_STATUS_OK if the NSEC3 RRs deny the existence, error code * containing the reason they do not otherwise */ ldns_status ldns_dnssec_verify_denial_nsec3(ldns_rr *rr, ldns_rr_list *nsecs, ldns_rr_list *rrsigs, ldns_pkt_rcode packet_rcode, ldns_rr_type packet_qtype, bool packet_nodata); /** * Same as ldns_status ldns_dnssec_verify_denial_nsec3 but also returns * the nsec rr that matched. * * \param[in] rr The (query) RR to check the denial of existence for * \param[in] nsecs The list of NSEC3 RRs that are supposed to deny the * existence of the RR * \param[in] rrsigs The RRSIG rr covering the NSEC RRs * \param[in] packet_rcode The RCODE value of the packet that provided the * NSEC3 RRs * \param[in] packet_qtype The original query RR type * \param[in] packet_nodata True if the providing packet had an empty ANSWER * section * \param[in] match On match, the given (reference to a) pointer will be set * to point to the matching nsec resource record. * \return LDNS_STATUS_OK if the NSEC3 RRs deny the existence, error code * containing the reason they do not otherwise */ ldns_status ldns_dnssec_verify_denial_nsec3_match(ldns_rr *rr, ldns_rr_list *nsecs, ldns_rr_list *rrsigs, ldns_pkt_rcode packet_rcode, ldns_rr_type packet_qtype, bool packet_nodata, ldns_rr **match); /** * Verifies the already processed data in the buffers * This function should probably not be used directly. * * \param[in] rawsig_buf Buffer containing signature data to use * \param[in] verify_buf Buffer containing data to verify * \param[in] key_buf Buffer containing key data to use * \param[in] algo Signing algorithm * \return status LDNS_STATUS_OK if the data verifies. Error if not. */ ldns_status ldns_verify_rrsig_buffers(ldns_buffer *rawsig_buf, ldns_buffer *verify_buf, ldns_buffer *key_buf, uint8_t algo); /** * Like ldns_verify_rrsig_buffers, but uses raw data. * * \param[in] sig signature data to use * \param[in] siglen length of signature data to use * \param[in] verify_buf Buffer containing data to verify * \param[in] key key data to use * \param[in] keylen length of key data to use * \param[in] algo Signing algorithm * \return status LDNS_STATUS_OK if the data verifies. Error if not. */ ldns_status ldns_verify_rrsig_buffers_raw(unsigned char* sig, size_t siglen, ldns_buffer *verify_buf, unsigned char* key, size_t keylen, uint8_t algo); /** * Verifies an rrsig. All keys in the keyset are tried. * \param[in] rrset the rrset to check * \param[in] rrsig the signature of the rrset * \param[in] keys the keys to try * \param[out] good_keys if this is a (initialized) list, the pointer to keys * from keys that validate one of the signatures * are added to it * \return a list of keys which validate the rrsig + rrset. Returns * status LDNS_STATUS_OK if at least one key matched. Else an error. */ ldns_status ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_list *keys, ldns_rr_list *good_keys); /** * Verifies an rrsig. All keys in the keyset are tried. * \param[in] rrset the rrset to check * \param[in] rrsig the signature of the rrset * \param[in] keys the keys to try * \param[in] check_time the time for which the validation is performed * \param[out] good_keys if this is a (initialized) list, the pointer to keys * from keys that validate one of the signatures * are added to it * \return a list of keys which validate the rrsig + rrset. Returns * status LDNS_STATUS_OK if at least one key matched. Else an error. */ ldns_status ldns_verify_rrsig_keylist_time( ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_list *keys, time_t check_time, ldns_rr_list *good_keys); /** * Verifies an rrsig. All keys in the keyset are tried. Time is not checked. * \param[in] rrset the rrset to check * \param[in] rrsig the signature of the rrset * \param[in] keys the keys to try * \param[out] good_keys if this is a (initialized) list, the pointer to keys * from keys that validate one of the signatures * are added to it * \return a list of keys which validate the rrsig + rrset. Returns * status LDNS_STATUS_OK if at least one key matched. Else an error. */ ldns_status ldns_verify_rrsig_keylist_notime(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_list *keys, ldns_rr_list *good_keys); /** * verify an rrsig with 1 key * \param[in] rrset the rrset * \param[in] rrsig the rrsig to verify * \param[in] key the key to use * \return status message wether verification succeeded. */ ldns_status ldns_verify_rrsig(ldns_rr_list *rrset, ldns_rr *rrsig, ldns_rr *key); /** * verify an rrsig with 1 key * \param[in] rrset the rrset * \param[in] rrsig the rrsig to verify * \param[in] key the key to use * \param[in] check_time the time for which the validation is performed * \return status message wether verification succeeded. */ ldns_status ldns_verify_rrsig_time( ldns_rr_list *rrset, ldns_rr *rrsig, ldns_rr *key, time_t check_time); #if LDNS_BUILD_CONFIG_HAVE_SSL /** * verifies a buffer with signature data for a buffer with rrset data * with an EVP_PKEY * * \param[in] sig the signature data * \param[in] rrset the rrset data, sorted and processed for verification * \param[in] key the EVP key structure * \param[in] digest_type The digest type of the signature */ ldns_status ldns_verify_rrsig_evp(ldns_buffer *sig, ldns_buffer *rrset, EVP_PKEY *key, const EVP_MD *digest_type); /** * Like ldns_verify_rrsig_evp, but uses raw signature data. * \param[in] sig the signature data, wireformat uncompressed * \param[in] siglen length of the signature data * \param[in] rrset the rrset data, sorted and processed for verification * \param[in] key the EVP key structure * \param[in] digest_type The digest type of the signature */ ldns_status ldns_verify_rrsig_evp_raw(unsigned char *sig, size_t siglen, ldns_buffer *rrset, EVP_PKEY *key, const EVP_MD *digest_type); #endif /** * verifies a buffer with signature data (DSA) for a buffer with rrset data * with a buffer with key data. * * \param[in] sig the signature data * \param[in] rrset the rrset data, sorted and processed for verification * \param[in] key the key data */ ldns_status ldns_verify_rrsig_dsa(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key); /** * verifies a buffer with signature data (RSASHA1) for a buffer with rrset data * with a buffer with key data. * * \param[in] sig the signature data * \param[in] rrset the rrset data, sorted and processed for verification * \param[in] key the key data */ ldns_status ldns_verify_rrsig_rsasha1(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key); /** * verifies a buffer with signature data (RSAMD5) for a buffer with rrset data * with a buffer with key data. * * \param[in] sig the signature data * \param[in] rrset the rrset data, sorted and processed for verification * \param[in] key the key data */ ldns_status ldns_verify_rrsig_rsamd5(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key); /** * Like ldns_verify_rrsig_dsa, but uses raw signature and key data. * \param[in] sig raw uncompressed wireformat signature data * \param[in] siglen length of signature data * \param[in] rrset ldns buffer with prepared rrset data. * \param[in] key raw uncompressed wireformat key data * \param[in] keylen length of key data */ ldns_status ldns_verify_rrsig_dsa_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen); /** * Like ldns_verify_rrsig_rsasha1, but uses raw signature and key data. * \param[in] sig raw uncompressed wireformat signature data * \param[in] siglen length of signature data * \param[in] rrset ldns buffer with prepared rrset data. * \param[in] key raw uncompressed wireformat key data * \param[in] keylen length of key data */ ldns_status ldns_verify_rrsig_rsasha1_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen); /** * Like ldns_verify_rrsig_rsasha256, but uses raw signature and key data. * \param[in] sig raw uncompressed wireformat signature data * \param[in] siglen length of signature data * \param[in] rrset ldns buffer with prepared rrset data. * \param[in] key raw uncompressed wireformat key data * \param[in] keylen length of key data */ ldns_status ldns_verify_rrsig_rsasha256_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen); /** * Like ldns_verify_rrsig_rsasha512, but uses raw signature and key data. * \param[in] sig raw uncompressed wireformat signature data * \param[in] siglen length of signature data * \param[in] rrset ldns buffer with prepared rrset data. * \param[in] key raw uncompressed wireformat key data * \param[in] keylen length of key data */ ldns_status ldns_verify_rrsig_rsasha512_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen); /** * Like ldns_verify_rrsig_rsamd5, but uses raw signature and key data. * \param[in] sig raw uncompressed wireformat signature data * \param[in] siglen length of signature data * \param[in] rrset ldns buffer with prepared rrset data. * \param[in] key raw uncompressed wireformat key data * \param[in] keylen length of key data */ ldns_status ldns_verify_rrsig_rsamd5_raw(unsigned char* sig, size_t siglen, ldns_buffer* rrset, unsigned char* key, size_t keylen); #ifdef __cplusplus } #endif #endif Net-LDNS-0.75/include/ldns/dnssec_zone.h000644 000770 000024 00000034555 12471046240 020376 0ustar00calledstaff000000 000000 /* * special zone file structures and functions for better dnssec handling * * A zone contains a SOA dnssec_zone_rrset, and an AVL tree of 'normal' * dnssec_zone_rrsets, indexed by name and type */ #ifndef LDNS_DNSSEC_ZONE_H #define LDNS_DNSSEC_ZONE_H #include #include #ifdef __cplusplus extern "C" { #endif /** * Singly linked list of rrs */ typedef struct ldns_struct_dnssec_rrs ldns_dnssec_rrs; struct ldns_struct_dnssec_rrs { ldns_rr *rr; ldns_dnssec_rrs *next; }; /** * Singly linked list of RRsets */ typedef struct ldns_struct_dnssec_rrsets ldns_dnssec_rrsets; struct ldns_struct_dnssec_rrsets { ldns_dnssec_rrs *rrs; ldns_rr_type type; ldns_dnssec_rrs *signatures; ldns_dnssec_rrsets *next; }; /** * Structure containing all resource records for a domain name * Including the derived NSEC3, if present */ typedef struct ldns_struct_dnssec_name ldns_dnssec_name; struct ldns_struct_dnssec_name { /** * pointer to a dname containing the name. * Usually points to the owner name of the first RR of the first RRset */ ldns_rdf *name; /** * Usually, the name is a pointer to the owner name of the first rr for * this name, but sometimes there is no actual data to point to, * for instance in * names representing empty nonterminals. If so, set alloced to true to * indicate that this data must also be freed when the name is freed */ bool name_alloced; /** * The rrsets for this name */ ldns_dnssec_rrsets *rrsets; /** * NSEC pointing to the next name (or NSEC3 pointing to the next NSEC3) */ ldns_rr *nsec; /** * signatures for the NSEC record */ ldns_dnssec_rrs *nsec_signatures; /** * Unlike what the name is_glue suggests, this field is set to true by * ldns_dnssec_zone_mark_glue() or ldns_dnssec_zone_mark_and_get_glue() * when the name, this dnssec_name struct represents, is occluded. * Names that contain other occluded rrsets and records with glue on * the delegation point will NOT have this bool set to true. * This field should NOT be read directly, but only via the * ldns_dnssec_name_is_glue() function! */ bool is_glue; /** * pointer to store the hashed name (only used when in an NSEC3 zone */ ldns_rdf *hashed_name; }; /** * Structure containing a dnssec zone */ struct ldns_struct_dnssec_zone { /** points to the name containing the SOA RR */ ldns_dnssec_name *soa; /** tree of ldns_dnssec_names */ ldns_rbtree_t *names; /** tree of ldns_dnssec_names by nsec3 hashes (when applicible) */ ldns_rbtree_t *hashed_names; /** points to the first added NSEC3 rr whose parameters will be * assumed for all subsequent NSEC3 rr's and which will be used * to calculate hashed names */ ldns_rr *_nsec3params; }; typedef struct ldns_struct_dnssec_zone ldns_dnssec_zone; /** * Creates a new entry for 1 pointer to an rr and 1 pointer to the next rrs * \return the allocated data */ ldns_dnssec_rrs *ldns_dnssec_rrs_new(void); /** * Frees the list of rrs, but *not* the individual ldns_rr records * contained in the list * * \param[in] rrs the data structure to free */ void ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs); /** * Frees the list of rrs, and the individual ldns_rr records * contained in the list * * \param[in] rrs the data structure to free */ void ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs); /** * Adds an RR to the list of RRs. The list will remain ordered. * If an equal RR already exists, this RR will not be added. * * \param[in] rrs the list to add to * \param[in] rr the RR to add * \return LDNS_STATUS_OK on success */ ldns_status ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr); /** * Prints the given rrs to the file descriptor * * \param[in] out the file descriptor to print to * \param[in] rrs the list of RRs to print */ void ldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs); /** * Prints the given rrs to the file descriptor * * \param[in] out the file descriptor to print to * \param[in] fmt the format of the textual representation * \param[in] rrs the list of RRs to print */ void ldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_rrs *rrs); /** * Creates a new list (entry) of RRsets * \return the newly allocated structure */ ldns_dnssec_rrsets *ldns_dnssec_rrsets_new(void); /** * Frees the list of rrsets and their rrs, but *not* the ldns_rr * records in the sets * * \param[in] rrsets the data structure to free */ void ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets); /** * Frees the list of rrsets and their rrs, and the ldns_rr * records in the sets * * \param[in] rrsets the data structure to free */ void ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets); /** * Returns the rr type of the rrset (that is head of the given list) * * \param[in] rrsets the rrset to get the type of * \return the rr type */ ldns_rr_type ldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets); /** * Sets the RR type of the rrset (that is head of the given list) * * \param[in] rrsets the rrset to set the type of * \param[in] type the type to set * \return LDNS_STATUS_OK on success */ ldns_status ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets, ldns_rr_type type); /** * Add an ldns_rr to the corresponding RRset in the given list of RRsets. * If it is not present, add it as a new RRset with 1 record. * * \param[in] rrsets the list of rrsets to add the RR to * \param[in] rr the rr to add to the list of rrsets * \return LDNS_STATUS_OK on success */ ldns_status ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr); /** * Print the given list of rrsets to the fiven file descriptor * * \param[in] out the file descriptor to print to * \param[in] rrsets the list of RRsets to print * \param[in] follow if set to false, only print the first RRset */ void ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow); /** * Print the given list of rrsets to the fiven file descriptor * * \param[in] out the file descriptor to print to * \param[in] fmt the format of the textual representation * \param[in] rrsets the list of RRsets to print * \param[in] follow if set to false, only print the first RRset */ void ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_rrsets *rrsets, bool follow); /** * Create a new data structure for a dnssec name * \return the allocated structure */ ldns_dnssec_name *ldns_dnssec_name_new(void); /** * Create a new data structure for a dnssec name for the given RR * * \param[in] rr the RR to derive properties from, and to add to the name */ ldns_dnssec_name *ldns_dnssec_name_new_frm_rr(ldns_rr *rr); /** * Frees the name structure and its rrs and rrsets. * Individual ldns_rr records therein are not freed * * \param[in] name the structure to free */ void ldns_dnssec_name_free(ldns_dnssec_name *name); /** * Frees the name structure and its rrs and rrsets. * Individual ldns_rr records contained in the name are also freed * * \param[in] name the structure to free */ void ldns_dnssec_name_deep_free(ldns_dnssec_name *name); /** * Returns the domain name of the given dnssec_name structure * * \param[in] name the dnssec name to get the domain name from * \return the domain name */ ldns_rdf *ldns_dnssec_name_name(ldns_dnssec_name *name); /** * Sets the domain name of the given dnssec_name structure * * \param[in] name the dnssec name to set the domain name of * \param[in] dname the domain name to set it to. This data is *not* copied. */ void ldns_dnssec_name_set_name(ldns_dnssec_name *name, ldns_rdf *dname); /** * Returns if dnssec_name structure is marked as glue. * The ldns_dnssec_zone_mark_glue() function has to be called on a zone before * using this function. * Only names that have only glue rrsets will be marked. * Names that have other occluded rrsets and names containing glue on the * delegation point will NOT be marked! * * \param[in] name the dnssec name to get the domain name from * \return true if the structure is marked as glue, false otherwise. */ bool ldns_dnssec_name_is_glue(ldns_dnssec_name *name); /** * Sets the NSEC(3) RR of the given dnssec_name structure * * \param[in] name the dnssec name to set the domain name of * \param[in] nsec the nsec rr to set it to. This data is *not* copied. */ void ldns_dnssec_name_set_nsec(ldns_dnssec_name *name, ldns_rr *nsec); /** * Compares the domain names of the two arguments in their * canonical ordening. * * \param[in] a The first dnssec_name to compare * \param[in] b The second dnssec_name to compare * \return -1 if the domain name of a comes before that of b in canonical * ordening, 1 if it is the other way around, and 0 if they are * equal */ int ldns_dnssec_name_cmp(const void *a, const void *b); /** * Inserts the given rr at the right place in the current dnssec_name * No checking is done whether the name matches * * \param[in] name The ldns_dnssec_name to add the RR to * \param[in] rr The RR to add * \return LDNS_STATUS_OK on success, error code otherwise */ ldns_status ldns_dnssec_name_add_rr(ldns_dnssec_name *name, ldns_rr *rr); /** * Find the RRset with the given type in within this name structure * * \param[in] name the name to find the RRset in * \param[in] type the type of the RRset to find * \return the RRset, or NULL if not present */ ldns_dnssec_rrsets *ldns_dnssec_name_find_rrset(ldns_dnssec_name *name, ldns_rr_type type); /** * Find the RRset with the given name and type in the zone * * \param[in] zone the zone structure to find the RRset in * \param[in] dname the domain name of the RRset to find * \param[in] type the type of the RRset to find * \return the RRset, or NULL if not present */ ldns_dnssec_rrsets *ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone, ldns_rdf *dname, ldns_rr_type type); /** * Prints the RRs in the dnssec name structure to the given * file descriptor * * \param[in] out the file descriptor to print to * \param[in] name the name structure to print the contents of */ void ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name); /** * Prints the RRs in the dnssec name structure to the given * file descriptor * * \param[in] out the file descriptor to print to * \param[in] fmt the format of the textual representation * \param[in] name the name structure to print the contents of */ void ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_name *name); /** * Creates a new dnssec_zone structure * \return the allocated structure */ ldns_dnssec_zone *ldns_dnssec_zone_new(void); /** * Create a new dnssec zone from a file. * \param[out] z the new zone * \param[in] *fp the filepointer to use * \param[in] *origin the zones' origin * \param[in] c default class to use (IN) * \param[in] ttl default ttl to use * * \return ldns_status mesg with an error or LDNS_STATUS_OK */ ldns_status ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, uint32_t ttl, ldns_rr_class c); /** * Create a new dnssec zone from a file, keep track of the line numbering * \param[out] z the new zone * \param[in] *fp the filepointer to use * \param[in] *origin the zones' origin * \param[in] ttl default ttl to use * \param[in] c default class to use (IN) * \param[out] line_nr used for error msg, to get to the line number * * \return ldns_status mesg with an error or LDNS_STATUS_OK */ ldns_status ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, uint32_t ttl, ldns_rr_class c, int* line_nr); /** * Frees the given zone structure, and its rbtree of dnssec_names * Individual ldns_rr RRs within those names are *not* freed * \param[in] *zone the zone to free */ void ldns_dnssec_zone_free(ldns_dnssec_zone *zone); /** * Frees the given zone structure, and its rbtree of dnssec_names * Individual ldns_rr RRs within those names are also freed * \param[in] *zone the zone to free */ void ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone); /** * Adds the given RR to the zone. * It find whether there is a dnssec_name with that name present. * If so, add it to that, if not create a new one. * Special handling of NSEC and RRSIG provided * * \param[in] zone the zone to add the RR to * \param[in] rr The RR to add * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr); /** * Prints the rbtree of ldns_dnssec_name structures to the file descriptor * * \param[in] out the file descriptor to print the names to * \param[in] tree the tree of ldns_dnssec_name structures to print * \param[in] print_soa if true, print SOA records, if false, skip them */ void ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa); /** * Prints the rbtree of ldns_dnssec_name structures to the file descriptor * * \param[in] out the file descriptor to print the names to * \param[in] fmt the format of the textual representation * \param[in] tree the tree of ldns_dnssec_name structures to print * \param[in] print_soa if true, print SOA records, if false, skip them */ void ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_rbtree_t *tree, bool print_soa); /** * Prints the complete zone to the given file descriptor * * \param[in] out the file descriptor to print to * \param[in] zone the dnssec_zone to print */ void ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone); /** * Prints the complete zone to the given file descriptor * * \param[in] out the file descriptor to print to * \param[in] fmt the format of the textual representation * \param[in] zone the dnssec_zone to print */ void ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_zone *zone); /** * Adds explicit dnssec_name structures for the empty nonterminals * in this zone. (this is needed for NSEC3 generation) * * \param[in] zone the zone to check for empty nonterminals * return LDNS_STATUS_OK on success. */ ldns_status ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone); /** * If a NSEC3PARAM is available in the apex, walks the zone and returns true * on the first optout nsec3. * * \param[in] zone the zone to check for nsec3 optout records * return true when the zone has at least one nsec3 optout record. */ bool ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone); #ifdef __cplusplus } #endif #endif Net-LDNS-0.75/include/ldns/duration.h000644 000770 000024 00000005650 12471046240 017703 0ustar00calledstaff000000 000000 /* * $Id: duration.h 4341 2011-01-31 15:21:09Z matthijs $ * * Copyright (c) 2009 NLNet Labs. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * * This file is copied from the OpenDNSSEC source repository * and only slightly adapted to make it fit. */ /** * * Durations. */ #ifndef LDNS_DURATION_H #define LDNS_DURATION_H #include #include /** * Duration. * */ typedef struct ldns_duration_struct ldns_duration_type; struct ldns_duration_struct { time_t years; time_t months; time_t weeks; time_t days; time_t hours; time_t minutes; time_t seconds; }; /** * Create a new 'instant' duration. * \return ldns_duration_type* created duration * */ ldns_duration_type* ldns_duration_create(void); /** * Compare durations. * \param[in] d1 one duration * \param[in] d2 another duration * \return int 0 if equal, -1 if d1 < d2, 1 if d2 < d1 * */ int ldns_duration_compare(ldns_duration_type* d1, ldns_duration_type* d2); /** * Create a duration from string. * \param[in] str string-format duration * \return ldns_duration_type* created duration * */ ldns_duration_type* ldns_duration_create_from_string(const char* str); /** * Convert a duration to a string. * \param[in] duration duration to be converted * \return char* string-format duration * */ char* ldns_duration2string(ldns_duration_type* duration); /** * Convert a duration to a time. * \param[in] duration duration to be converted * \return time_t time-format duration * */ time_t ldns_duration2time(ldns_duration_type* duration); /** * Clean up duration. * \param[in] duration duration to be cleaned up * */ void ldns_duration_cleanup(ldns_duration_type* duration); #endif /* LDNS_DURATION_H */ Net-LDNS-0.75/include/ldns/error.h000644 000770 000024 00000010002 12471046240 017172 0ustar00calledstaff000000 000000 /** * \file error.h * * Defines error numbers and functions to translate those to a readable string. * */ /** * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ #ifndef LDNS_ERROR_H #define LDNS_ERROR_H #include #ifdef __cplusplus extern "C" { #endif enum ldns_enum_status { LDNS_STATUS_OK, LDNS_STATUS_EMPTY_LABEL, LDNS_STATUS_LABEL_OVERFLOW, LDNS_STATUS_DOMAINNAME_OVERFLOW, LDNS_STATUS_DOMAINNAME_UNDERFLOW, LDNS_STATUS_DDD_OVERFLOW, LDNS_STATUS_PACKET_OVERFLOW, LDNS_STATUS_INVALID_POINTER, LDNS_STATUS_MEM_ERR, LDNS_STATUS_INTERNAL_ERR, LDNS_STATUS_SSL_ERR, LDNS_STATUS_ERR, LDNS_STATUS_INVALID_INT, LDNS_STATUS_INVALID_IP4, LDNS_STATUS_INVALID_IP6, LDNS_STATUS_INVALID_STR, LDNS_STATUS_INVALID_B32_EXT, LDNS_STATUS_INVALID_B64, LDNS_STATUS_INVALID_HEX, LDNS_STATUS_INVALID_TIME, LDNS_STATUS_NETWORK_ERR, LDNS_STATUS_ADDRESS_ERR, LDNS_STATUS_FILE_ERR, LDNS_STATUS_UNKNOWN_INET, LDNS_STATUS_NOT_IMPL, LDNS_STATUS_NULL, LDNS_STATUS_CRYPTO_UNKNOWN_ALGO, LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL, LDNS_STATUS_CRYPTO_NO_RRSIG, LDNS_STATUS_CRYPTO_NO_DNSKEY, LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY, LDNS_STATUS_CRYPTO_NO_DS, LDNS_STATUS_CRYPTO_NO_TRUSTED_DS, LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY, LDNS_STATUS_CRYPTO_VALIDATED, LDNS_STATUS_CRYPTO_BOGUS, LDNS_STATUS_CRYPTO_SIG_EXPIRED, LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED, LDNS_STATUS_CRYPTO_TSIG_BOGUS, LDNS_STATUS_CRYPTO_TSIG_ERR, LDNS_STATUS_CRYPTO_EXPIRATION_BEFORE_INCEPTION, LDNS_STATUS_CRYPTO_TYPE_COVERED_ERR, LDNS_STATUS_ENGINE_KEY_NOT_LOADED, LDNS_STATUS_NSEC3_ERR, LDNS_STATUS_RES_NO_NS, LDNS_STATUS_RES_QUERY, LDNS_STATUS_WIRE_INCOMPLETE_HEADER, LDNS_STATUS_WIRE_INCOMPLETE_QUESTION, LDNS_STATUS_WIRE_INCOMPLETE_ANSWER, LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY, LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL, LDNS_STATUS_NO_DATA, LDNS_STATUS_CERT_BAD_ALGORITHM, LDNS_STATUS_SYNTAX_TYPE_ERR, LDNS_STATUS_SYNTAX_CLASS_ERR, LDNS_STATUS_SYNTAX_TTL_ERR, LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL, LDNS_STATUS_SYNTAX_RDATA_ERR, LDNS_STATUS_SYNTAX_DNAME_ERR, LDNS_STATUS_SYNTAX_VERSION_ERR, LDNS_STATUS_SYNTAX_ALG_ERR, LDNS_STATUS_SYNTAX_KEYWORD_ERR, LDNS_STATUS_SYNTAX_TTL, LDNS_STATUS_SYNTAX_ORIGIN, LDNS_STATUS_SYNTAX_INCLUDE, LDNS_STATUS_SYNTAX_EMPTY, LDNS_STATUS_SYNTAX_ITERATIONS_OVERFLOW, LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR, LDNS_STATUS_SYNTAX_INTEGER_OVERFLOW, LDNS_STATUS_SYNTAX_BAD_ESCAPE, LDNS_STATUS_SOCKET_ERROR, LDNS_STATUS_SYNTAX_ERR, LDNS_STATUS_DNSSEC_EXISTENCE_DENIED, LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED, LDNS_STATUS_DNSSEC_NSEC_WILDCARD_NOT_COVERED, LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND, LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG, LDNS_STATUS_MISSING_RDATA_FIELDS_KEY, LDNS_STATUS_CRYPTO_SIG_EXPIRED_WITHIN_MARGIN, LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED_WITHIN_MARGIN, LDNS_STATUS_DANE_STATUS_MESSAGES, LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE, LDNS_STATUS_DANE_UNKNOWN_SELECTOR, LDNS_STATUS_DANE_UNKNOWN_MATCHING_TYPE, LDNS_STATUS_DANE_UNKNOWN_PROTOCOL, LDNS_STATUS_DANE_UNKNOWN_TRANSPORT, LDNS_STATUS_DANE_MISSING_EXTRA_CERTS, LDNS_STATUS_DANE_EXTRA_CERTS_NOT_USED, LDNS_STATUS_DANE_OFFSET_OUT_OF_RANGE, LDNS_STATUS_DANE_INSECURE, LDNS_STATUS_DANE_BOGUS, LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH, LDNS_STATUS_DANE_NON_CA_CERTIFICATE, LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE, LDNS_STATUS_DANE_PKIX_NO_SELF_SIGNED_TRUST_ANCHOR, LDNS_STATUS_EXISTS_ERR, LDNS_STATUS_INVALID_ILNP64, LDNS_STATUS_INVALID_EUI48, LDNS_STATUS_INVALID_EUI64, LDNS_STATUS_WIRE_RDATA_ERR, LDNS_STATUS_INVALID_TAG, LDNS_STATUS_TYPE_NOT_IN_BITMAP, LDNS_STATUS_INVALID_RDF_TYPE, LDNS_STATUS_RDATA_OVERFLOW }; typedef enum ldns_enum_status ldns_status; extern ldns_lookup_table ldns_error_str[]; /** * look up a descriptive text by each error. This function * could use a better name * \param[in] err ldns_status number * \return the string for that error */ const char *ldns_get_errorstr_by_id(ldns_status err); #ifdef __cplusplus } #endif #endif /* LDNS_ERROR_H */ Net-LDNS-0.75/include/ldns/higher.h000644 000770 000024 00000006441 12471046240 017323 0ustar00calledstaff000000 000000 /** * \file higher.h * * Specifies some higher level functions that could * be useful for certain applications */ /* * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ #ifndef LDNS_HIGHER_H #define LDNS_HIGHER_H #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Ask the resolver about name * and return all address records * \param[in] r the resolver to use * \param[in] name the name to look for * \param[in] c the class to use * \param[in] flags give some optional flags to the query */ ldns_rr_list *ldns_get_rr_list_addr_by_name(ldns_resolver *r, ldns_rdf *name, ldns_rr_class c, uint16_t flags); /** * ask the resolver about the address * and return the name * \param[in] r the resolver to use * \param[in] addr the addr to look for * \param[in] c the class to use * \param[in] flags give some optional flags to the query */ ldns_rr_list *ldns_get_rr_list_name_by_addr(ldns_resolver *r, ldns_rdf *addr, ldns_rr_class c, uint16_t flags); /** * wade through fp (a /etc/hosts like file) * and return a rr_list containing all the * defined hosts in there * \param[in] fp the file pointer to use * \return ldns_rr_list * with the names */ ldns_rr_list *ldns_get_rr_list_hosts_frm_fp(FILE *fp); /** * wade through fp (a /etc/hosts like file) * and return a rr_list containing all the * defined hosts in there * \param[in] fp the file pointer to use * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes) * \return ldns_rr_list * with the names */ ldns_rr_list *ldns_get_rr_list_hosts_frm_fp_l(FILE *fp, int *line_nr); /** * wade through fp (a /etc/hosts like file) * and return a rr_list containing all the * defined hosts in there * \param[in] filename the filename to use (NULL for /etc/hosts) * \return ldns_rr_list * with the names */ ldns_rr_list *ldns_get_rr_list_hosts_frm_file(char *filename); /** * This function is a wrapper function for ldns_get_rr_list_name_by_addr * and ldns_get_rr_list_addr_by_name. It's name is from the getaddrinfo() * library call. It tries to mimic that call, but without the lowlevel * stuff. * \param[in] res The resolver. If this value is NULL then a resolver will * be created by ldns_getaddrinfo. * \param[in] node the name or ip address to look up * \param[in] c the class to look in * \param[out] list put the found RR's in this list * \return the number of RR found. */ uint16_t ldns_getaddrinfo(ldns_resolver *res, ldns_rdf *node, ldns_rr_class c, ldns_rr_list **list); /** * Check if t is enumerated in the nsec type rdata * \param[in] nsec the NSEC Record to look in * \param[in] t the type to check for * \return true when t is found, otherwise return false */ bool ldns_nsec_type_check(ldns_rr *nsec, ldns_rr_type t); /** * Print a number of rdf's of the RR. The rdfnum-list must * be ended by -1, otherwise unpredictable things might happen. * rdfs may be printed multiple times * \param[in] fp FILE * to write to * \param[in] r RR to write * \param[in] rdfnum a list of rdf to print. */ void ldns_print_rr_rdf(FILE *fp, ldns_rr *r, int rdfnum, ...); #ifdef __cplusplus } #endif #endif /* LDNS_HIGHER_H */ Net-LDNS-0.75/include/ldns/host2str.h000644 000770 000024 00000075434 12471046240 017655 0ustar00calledstaff000000 000000 /** * host2str.h - txt presentation of RRs * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ /** * \file * * Contains functions to translate the main structures to their text * representation, as well as functions to print them. */ #ifndef LDNS_HOST2STR_H #define LDNS_HOST2STR_H #include #include #include #include #include #include #include #include #include #include "ldns/util.h" #ifdef __cplusplus extern "C" { #endif #define LDNS_APL_IP4 1 #define LDNS_APL_IP6 2 #define LDNS_APL_MASK 0x7f #define LDNS_APL_NEGATION 0x80 /** * Represent a NULL pointer (instead of a pointer to a ldns_rr as "; (null)" * as opposed to outputting nothing at all in such a case. */ /* Flag Name Flag Nr. Has data associated ---------------------------------------------------------------------*/ #define LDNS_COMMENT_NULLS (1 << 0) /** Show key id with DNSKEY RR's as comment */ #define LDNS_COMMENT_KEY_ID (1 << 1) /** Show if a DNSKEY is a ZSK or KSK as comment */ #define LDNS_COMMENT_KEY_TYPE (1 << 2) /** Show DNSKEY key size as comment */ #define LDNS_COMMENT_KEY_SIZE (1 << 3) /** Provide bubblebabble representation for DS RR's as comment */ #define LDNS_COMMENT_BUBBLEBABBLE (1 << 4) /** Show when a NSEC3 RR has the optout flag set as comment */ #define LDNS_COMMENT_FLAGS (1 << 5) /** Show the unhashed owner and next owner names for NSEC3 RR's as comment */ #define LDNS_COMMENT_NSEC3_CHAIN (1 << 6) /* yes */ /** Print mark up */ #define LDNS_COMMENT_LAYOUT (1 << 7) /** Also comment KEY_ID with RRSIGS **/ #define LDNS_COMMENT_RRSIGS (1 << 8) #define LDNS_FMT_ZEROIZE_RRSIGS (1 << 9) #define LDNS_FMT_PAD_SOA_SERIAL (1 << 10) #define LDNS_FMT_RFC3597 (1 << 11) /* yes */ #define LDNS_FMT_FLAGS_WITH_DATA 2 /** Show key id, type and size as comment for DNSKEY RR's */ #define LDNS_COMMENT_KEY (LDNS_COMMENT_KEY_ID \ |LDNS_COMMENT_KEY_TYPE\ |LDNS_COMMENT_KEY_SIZE) /** * Output format specifier * * Determines how Packets, Resource Records and Resource record data fiels are * formatted when printing or converting to string. * Currently it is only used to specify what aspects of a Resource Record are * annotated in the comment section of the textual representation the record. * This is speciefed with flags and potential exra data (such as for example * a lookup map of hashes to real names for annotation NSEC3 records). */ struct ldns_struct_output_format { /** Specification of how RR's should be formatted in text */ int flags; /** Potential extra data to be used with formatting RR's in text */ void *data; }; typedef struct ldns_struct_output_format ldns_output_format; /** * Output format struct with additional data for flags that use them. * This struct may not be initialized directly. Use ldns_output_format_init * to initialize. */ struct ldns_struct_output_format_storage { int flags; ldns_rbtree_t* hashmap; /* for LDNS_COMMENT_NSEC3_CHAIN */ ldns_rdf* bitmap; /* for LDNS_FMT_RFC3597 */ }; typedef struct ldns_struct_output_format_storage ldns_output_format_storage; /** * Standard output format record that disables commenting in the textual * representation of Resource Records completely. */ extern const ldns_output_format *ldns_output_format_nocomments; /** * Standard output format record that annotated only DNSKEY RR's with commenti * text. */ extern const ldns_output_format *ldns_output_format_onlykeyids; /** * The default output format record. Same as ldns_output_format_onlykeyids. */ extern const ldns_output_format *ldns_output_format_default; /** * Standard output format record that shows all DNSKEY related information in * the comment text, plus the optout flag when set with NSEC3's, plus the * bubblebabble representation of DS RR's. */ extern const ldns_output_format *ldns_output_format_bubblebabble; /** * Initialize output format storage to the default value. * \param[in] fmt A reference to an output_format_ storage struct * \return The initialized storage struct typecasted to ldns_output_format */ INLINE ldns_output_format* ldns_output_format_init(ldns_output_format_storage* fmt) { fmt->flags = ldns_output_format_default->flags; fmt->hashmap = NULL; fmt->bitmap = NULL; return (ldns_output_format*)fmt; } /** * Set an ouput format flag. */ INLINE void ldns_output_format_set(ldns_output_format* fmt, int flag) { fmt->flags |= flag; } /** * Clear an ouput format flag. */ INLINE void ldns_output_format_clear(ldns_output_format* fmt, int flag) { fmt->flags &= !flag; } /** * Makes sure the LDNS_FMT_RFC3597 is set in the output format. * Marks the type to be printed in RFC3597 format. * /param[in] fmt the output format to update * /param[in] the type to be printed in RFC3597 format * /return LDNS_STATUS_OK on success */ ldns_status ldns_output_format_set_type(ldns_output_format* fmt, ldns_rr_type type); /** * Makes sure the LDNS_FMT_RFC3597 is set in the output format. * Marks the type to not be printed in RFC3597 format. When no other types * have been marked before, all known types (except the given one) will be * marked for printing in RFC3597 format. * /param[in] fmt the output format to update * /param[in] the type not to be printed in RFC3597 format * /return LDNS_STATUS_OK on success */ ldns_status ldns_output_format_clear_type(ldns_output_format* fmt, ldns_rr_type type); /** * Converts an ldns packet opcode value to its mnemonic, and adds that * to the output buffer * \param[in] *output the buffer to add the data to * \param[in] opcode to find the string representation of * \return LDNS_STATUS_OK on success, or a buffer failure mode on error */ ldns_status ldns_pkt_opcode2buffer_str(ldns_buffer *output, ldns_pkt_opcode opcode); /** * Converts an ldns packet rcode value to its mnemonic, and adds that * to the output buffer * \param[in] *output the buffer to add the data to * \param[in] rcode to find the string representation of * \return LDNS_STATUS_OK on success, or a buffer failure mode on error */ ldns_status ldns_pkt_rcode2buffer_str(ldns_buffer *output, ldns_pkt_rcode rcode); /** * Converts an ldns algorithm type to its mnemonic, and adds that * to the output buffer * \param[in] *output the buffer to add the data to * \param[in] algorithm to find the string representation of * \return LDNS_STATUS_OK on success, or a buffer failure mode on error */ ldns_status ldns_algorithm2buffer_str(ldns_buffer *output, ldns_algorithm algorithm); /** * Converts an ldns certificate algorithm type to its mnemonic, * and adds that to the output buffer * \param[in] *output the buffer to add the data to * \param[in] cert_algorithm to find the string representation of * \return LDNS_STATUS_OK on success, or a buffer failure mode on error */ ldns_status ldns_cert_algorithm2buffer_str(ldns_buffer *output, ldns_cert_algorithm cert_algorithm); /** * Converts a packet opcode to its mnemonic and returns that as * an allocated null-terminated string. * Remember to free it. * * \param[in] opcode the opcode to convert to text * \return null terminated char * data, or NULL on error */ char *ldns_pkt_opcode2str(ldns_pkt_opcode opcode); /** * Converts a packet rcode to its mnemonic and returns that as * an allocated null-terminated string. * Remember to free it. * * \param[in] rcode the rcode to convert to text * \return null terminated char * data, or NULL on error */ char *ldns_pkt_rcode2str(ldns_pkt_rcode rcode); /** * Converts a signing algorithms to its mnemonic and returns that as * an allocated null-terminated string. * Remember to free it. * * \param[in] algorithm the algorithm to convert to text * \return null terminated char * data, or NULL on error */ char *ldns_pkt_algorithm2str(ldns_algorithm algorithm); /** * Converts a cert algorithm to its mnemonic and returns that as * an allocated null-terminated string. * Remember to free it. * * \param[in] cert_algorithm to convert to text * \return null terminated char * data, or NULL on error */ char *ldns_pkt_cert_algorithm2str(ldns_cert_algorithm cert_algorithm); /** * Converts an LDNS_RDF_TYPE_A rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_a(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_AAAA rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_aaaa(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_STR rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_str(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_B64 rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_b64(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_B32_EXT rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_b32_ext(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_HEX rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_hex(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_TYPE rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_type(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_CLASS rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_class(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_ALG rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_alg(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an ldns_rr_type value to its string representation, * and places it in the given buffer * \param[in] *output The buffer to add the data to * \param[in] type the ldns_rr_type to convert * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rr_type2buffer_str(ldns_buffer *output, const ldns_rr_type type); /** * Converts an ldns_rr_type value to its string representation, * and returns that string. For unknown types, the string * "TYPE" is returned. This function allocates data that must be * freed by the caller * \param[in] type the ldns_rr_type to convert * \return a newly allocated string */ char *ldns_rr_type2str(const ldns_rr_type type); /** * Converts an ldns_rr_class value to its string representation, * and places it in the given buffer * \param[in] *output The buffer to add the data to * \param[in] klass the ldns_rr_class to convert * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rr_class2buffer_str(ldns_buffer *output, const ldns_rr_class klass); /** * Converts an ldns_rr_class value to its string representation, * and returns that string. For unknown types, the string * "CLASS" is returned. This function allocates data that must be * freed by the caller * \param[in] klass the ldns_rr_class to convert * \return a newly allocated string */ char *ldns_rr_class2str(const ldns_rr_class klass); /** * Converts an LDNS_RDF_TYPE_CERT rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_cert_alg(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_LOC rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_UNKNOWN rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_unknown(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_NSAP rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_nsap(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_ATMA rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_atma(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_WKS rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_wks(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_NSEC rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_PERIOD rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_period(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_TSIGTIME rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_tsigtime(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_APL rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_apl(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_INT16_DATA rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_int16_data(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_IPSECKEY rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts the data in the rdata field to presentation * format (as char *) and appends it to the given buffer * * \param[in] output pointer to the buffer to append the data to * \param[in] rdf the pointer to the rdafa field containing the data * \return status */ ldns_status ldns_rdf2buffer_str(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts the data in the resource record to presentation * format (as char *) and appends it to the given buffer. * The presentation format of DNSKEY record is annotated with comments giving * the id, type and size of the key. * * \param[in] output pointer to the buffer to append the data to * \param[in] rr the pointer to the rr field to convert * \return status */ ldns_status ldns_rr2buffer_str(ldns_buffer *output, const ldns_rr *rr); /** * Converts the data in the resource record to presentation * format (as char *) and appends it to the given buffer. * The presentation format is annotated with comments giving * additional information on the record. * * \param[in] output pointer to the buffer to append the data to * \param[in] fmt how to format the textual representation of the * resource record. * \param[in] rr the pointer to the rr field to convert * \return status */ ldns_status ldns_rr2buffer_str_fmt(ldns_buffer *output, const ldns_output_format *fmt, const ldns_rr *rr); /** * Converts the data in the DNS packet to presentation * format (as char *) and appends it to the given buffer * * \param[in] output pointer to the buffer to append the data to * \param[in] pkt the pointer to the packet to convert * \return status */ ldns_status ldns_pkt2buffer_str(ldns_buffer *output, const ldns_pkt *pkt); /** * Converts the data in the DNS packet to presentation * format (as char *) and appends it to the given buffer * * \param[in] output pointer to the buffer to append the data to * \param[in] fmt how to format the textual representation of the packet * \param[in] pkt the pointer to the packet to convert * \return status */ ldns_status ldns_pkt2buffer_str_fmt(ldns_buffer *output, const ldns_output_format *fmt, const ldns_pkt *pkt); /** * Converts an LDNS_RDF_TYPE_NSEC3_SALT rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_nsec3_salt(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts the data in the DNS packet to presentation * format (as char *) and appends it to the given buffer * * \param[in] output pointer to the buffer to append the data to * \param[in] k the pointer to the private key to convert * \return status */ ldns_status ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k); /** * Converts an LDNS_RDF_TYPE_INT8 rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_int8(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_INT16 rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_int16(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_INT32 rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_int32(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_TIME rdata element to string format and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_time(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_ILNP64 rdata element to 4 hexadecimal numbers * separated by colons and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_ilnp64(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_EUI48 rdata element to 6 hexadecimal numbers * separated by dashes and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_eui48(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_EUI64 rdata element to 8 hexadecimal numbers * separated by dashes and adds it to the output buffer * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_eui64(ldns_buffer *output, const ldns_rdf *rdf); /** * Adds the LDNS_RDF_TYPE_TAG rdata to the output buffer, * provided it contains only alphanumeric characters. * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_tag(ldns_buffer *output, const ldns_rdf *rdf); /** * Adds the LDNS_RDF_TYPE_LONG_STR rdata to the output buffer, in-between * double quotes and all non printable characters properly escaped. * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_long_str(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts an LDNS_RDF_TYPE_HIP rdata element to presentation format for * the algorithm, HIT and Public Key and adds it the output buffer . * \param[in] *rdf The rdata to convert * \param[in] *output The buffer to add the data to * \return LDNS_STATUS_OK on success, and error status on failure */ ldns_status ldns_rdf2buffer_str_hip(ldns_buffer *output, const ldns_rdf *rdf); /** * Converts the data in the rdata field to presentation format and * returns that as a char *. * Remember to free it. * * \param[in] rdf The rdata field to convert * \return null terminated char * data, or NULL on error */ char *ldns_rdf2str(const ldns_rdf *rdf); /** * Converts the data in the resource record to presentation format and * returns that as a char *. * Remember to free it. * * \param[in] rr The rdata field to convert * \return null terminated char * data, or NULL on error */ char *ldns_rr2str(const ldns_rr *rr); /** * Converts the data in the resource record to presentation format and * returns that as a char *. * Remember to free it. * * \param[in] fmt how to format the resource record * \param[in] rr The rdata field to convert * \return null terminated char * data, or NULL on error */ char *ldns_rr2str_fmt(const ldns_output_format *fmt, const ldns_rr *rr); /** * Converts the data in the DNS packet to presentation format and * returns that as a char *. * Remember to free it. * * \param[in] pkt The rdata field to convert * \return null terminated char * data, or NULL on error */ char *ldns_pkt2str(const ldns_pkt *pkt); /** * Converts the data in the DNS packet to presentation format and * returns that as a char *. * Remember to free it. * * \param[in] fmt how to format the packet * \param[in] pkt The rdata field to convert * \return null terminated char * data, or NULL on error */ char *ldns_pkt2str_fmt(const ldns_output_format *fmt, const ldns_pkt *pkt); /** * Converts a private key to the test presentation fmt and * returns that as a char *. * Remember to free it. * * \param[in] k the key to convert to text * \return null terminated char * data, or NULL on error */ char *ldns_key2str(const ldns_key *k); /** * Converts a list of resource records to presentation format * and returns that as a char *. * Remember to free it. * * \param[in] rr_list the rr_list to convert to text * \return null terminated char * data, or NULL on error */ char *ldns_rr_list2str(const ldns_rr_list *rr_list); /** * Converts a list of resource records to presentation format * and returns that as a char *. * Remember to free it. * * \param[in] fmt how to format the list of resource records * \param[in] rr_list the rr_list to convert to text * \return null terminated char * data, or NULL on error */ char *ldns_rr_list2str_fmt( const ldns_output_format *fmt, const ldns_rr_list *rr_list); /** * Returns a copy of the data in the buffer as a null terminated * char * string. The returned string must be freed by the caller. * The buffer must be in write modus and may thus not have been flipped. * * \param[in] buffer buffer containing char * data * \return null terminated char * data, or NULL on error */ char *ldns_buffer2str(ldns_buffer *buffer); /** * Exports and returns the data in the buffer as a null terminated * char * string. The returned string must be freed by the caller. * The buffer must be in write modus and may thus not have been flipped. * The buffer is fixed after this function returns. * * \param[in] buffer buffer containing char * data * \return null terminated char * data, or NULL on error */ char *ldns_buffer_export2str(ldns_buffer *buffer); /** * Prints the data in the rdata field to the given file stream * (in presentation format) * * \param[in] output the file stream to print to * \param[in] rdf the rdata field to print * \return void */ void ldns_rdf_print(FILE *output, const ldns_rdf *rdf); /** * Prints the data in the resource record to the given file stream * (in presentation format) * * \param[in] output the file stream to print to * \param[in] rr the resource record to print * \return void */ void ldns_rr_print(FILE *output, const ldns_rr *rr); /** * Prints the data in the resource record to the given file stream * (in presentation format) * * \param[in] output the file stream to print to * \param[in] fmt format of the textual representation * \param[in] rr the resource record to print * \return void */ void ldns_rr_print_fmt(FILE *output, const ldns_output_format *fmt, const ldns_rr *rr); /** * Prints the data in the DNS packet to the given file stream * (in presentation format) * * \param[in] output the file stream to print to * \param[in] pkt the packet to print * \return void */ void ldns_pkt_print(FILE *output, const ldns_pkt *pkt); /** * Prints the data in the DNS packet to the given file stream * (in presentation format) * * \param[in] output the file stream to print to * \param[in] fmt format of the textual representation * \param[in] pkt the packet to print * \return void */ void ldns_pkt_print_fmt(FILE *output, const ldns_output_format *fmt, const ldns_pkt *pkt); /** * Converts a rr_list to presentation format and appends it to * the output buffer * \param[in] output the buffer to append output to * \param[in] list the ldns_rr_list to print * \return ldns_status */ ldns_status ldns_rr_list2buffer_str(ldns_buffer *output, const ldns_rr_list *list); /** * Converts a rr_list to presentation format and appends it to * the output buffer * \param[in] output the buffer to append output to * \param[in] fmt format of the textual representation * \param[in] list the ldns_rr_list to print * \return ldns_status */ ldns_status ldns_rr_list2buffer_str_fmt(ldns_buffer *output, const ldns_output_format *fmt, const ldns_rr_list *list); /** * Converts the header of a packet to presentation format and appends it to * the output buffer * \param[in] output the buffer to append output to * \param[in] pkt the packet to convert the header of * \return ldns_status */ ldns_status ldns_pktheader2buffer_str(ldns_buffer *output, const ldns_pkt *pkt); /** * print a rr_list to output * \param[in] output the fd to print to * \param[in] list the rr_list to print */ void ldns_rr_list_print(FILE *output, const ldns_rr_list *list); /** * print a rr_list to output * \param[in] output the fd to print to * \param[in] fmt format of the textual representation * \param[in] list the rr_list to print */ void ldns_rr_list_print_fmt(FILE *output, const ldns_output_format *fmt, const ldns_rr_list *list); /** * Print a resolver (in sofar that is possible) state * to output. * \param[in] output the fd to print to * \param[in] r the resolver to print */ void ldns_resolver_print(FILE *output, const ldns_resolver *r); /** * Print a resolver (in sofar that is possible) state * to output. * \param[in] output the fd to print to * \param[in] fmt format of the textual representation * \param[in] r the resolver to print */ void ldns_resolver_print_fmt(FILE *output, const ldns_output_format *fmt, const ldns_resolver *r); /** * Print a zone structure * to output. Note the SOA record * is included in this output * \param[in] output the fd to print to * \param[in] z the zone to print */ void ldns_zone_print(FILE *output, const ldns_zone *z); /** * Print a zone structure * to output. Note the SOA record * is included in this output * \param[in] output the fd to print to * \param[in] fmt format of the textual representation * \param[in] z the zone to print */ void ldns_zone_print_fmt(FILE *output, const ldns_output_format *fmt, const ldns_zone *z); /** * Print the ldns_rdf containing a dname to the buffer * \param[in] output the buffer to print to * \param[in] dname the dname to print * \return ldns_status message if the printing succeeded */ ldns_status ldns_rdf2buffer_str_dname(ldns_buffer *output, const ldns_rdf *dname); #ifdef __cplusplus } #endif #endif /* LDNS_HOST2STR_H */ Net-LDNS-0.75/include/ldns/host2wire.h000644 000770 000024 00000014620 12471046240 020001 0ustar00calledstaff000000 000000 /* * host2wire.h - 2wire conversion routines * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ /** * \file * * Contains all functions to translate the main structures to wire format */ #ifndef LDNS_HOST2WIRE_H #define LDNS_HOST2WIRE_H #include #include #include #include #include #include #include #include "ldns/util.h" #ifdef __cplusplus extern "C" { #endif /** * Copies the dname data to the buffer in wire format * \param[out] *buffer buffer to append the result to * \param[in] *name rdata dname to convert * \return ldns_status */ ldns_status ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name); /** * Copies the dname data to the buffer in wire format * \param[out] *buffer buffer to append the result to * \param[in] *name rdata dname to convert * \param[out] *compression_data data structure holding state for compression * \return ldns_status */ ldns_status ldns_dname2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *name, ldns_rbtree_t *compression_data); /** * Copies the rdata data to the buffer in wire format * \param[out] *output buffer to append the result to * \param[in] *rdf rdata to convert * \return ldns_status */ ldns_status ldns_rdf2buffer_wire(ldns_buffer *output, const ldns_rdf *rdf); /** * Copies the rdata data to the buffer in wire format * \param[out] *output buffer to append the result to * \param[in] *rdf rdata to convert * \param[out] *compression_data data structure holding state for compression * \return ldns_status */ ldns_status ldns_rdf2buffer_wire_compress(ldns_buffer *output, const ldns_rdf *rdf, ldns_rbtree_t *compression_data); /** * Copies the rdata data to the buffer in wire format * If the rdata is a dname, the letters will be lowercased * during the conversion * \param[out] *output buffer to append the result to * \param[in] *rdf rdata to convert * \return ldns_status */ ldns_status ldns_rdf2buffer_wire_canonical(ldns_buffer *output, const ldns_rdf *rdf); /** * Copies the rr data to the buffer in wire format * \param[out] *output buffer to append the result to * \param[in] *rr resource record to convert * \param[in] section the section in the packet this rr is supposed to be in * (to determine whether to add rdata or not) * \return ldns_status */ ldns_status ldns_rr2buffer_wire(ldns_buffer *output, const ldns_rr *rr, int section); /** * Copies the rr data to the buffer in wire format while doing DNAME compression * \param[out] *output buffer to append the result to * \param[in] *rr resource record to convert * \param[in] section the section in the packet this rr is supposed to be in * (to determine whether to add rdata or not) * \param[out] *compression_data data structure holding state information for compression * \return ldns_status */ ldns_status ldns_rr2buffer_wire_compress(ldns_buffer *output, const ldns_rr *rr, int section, ldns_rbtree_t *compression_data); /** * Copies the rr data to the buffer in wire format, in canonical format * according to RFC3597 (every dname in rdata fields of RR's mentioned in * that RFC will be lowercased) * \param[out] *output buffer to append the result to * \param[in] *rr resource record to convert * \param[in] section the section in the packet this rr is supposed to be in * (to determine whether to add rdata or not) * \return ldns_status */ ldns_status ldns_rr2buffer_wire_canonical(ldns_buffer *output, const ldns_rr *rr, int section); /** * Converts a rrsig to wireformat BUT EXCLUDE the rrsig rdata * This is needed in DNSSEC verification * \param[out] output buffer to append the result to * \param[in] sigrr signature rr to operate on * \return ldns_status */ ldns_status ldns_rrsig2buffer_wire(ldns_buffer *output, const ldns_rr *sigrr); /** * Converts an rr's rdata to wireformat, while excluding * the ownername and all the stuff before the rdata. * This is needed in DNSSEC keytag calculation, the ds * calcalution from the key and maybe elsewhere. * * \param[out] *output buffer where to put the result * \param[in] *rr rr to operate on * \return ldns_status */ ldns_status ldns_rr_rdata2buffer_wire(ldns_buffer *output, const ldns_rr *rr); /** * Copies the packet data to the buffer in wire format * \param[out] *output buffer to append the result to * \param[in] *pkt packet to convert * \return ldns_status */ ldns_status ldns_pkt2buffer_wire(ldns_buffer *output, const ldns_pkt *pkt); /** * Copies the rr_list data to the buffer in wire format * \param[out] *output buffer to append the result to * \param[in] *rrlist rr_list to to convert * \return ldns_status */ ldns_status ldns_rr_list2buffer_wire(ldns_buffer *output, const ldns_rr_list *rrlist); /** * Allocates an array of uint8_t at dest, and puts the wireformat of the * given rdf in that array. The result_size value contains the * length of the array, if it succeeds, and 0 otherwise (in which case * the function also returns NULL) * * \param[out] dest pointer to the array of bytes to be created * \param[in] rdf the rdata field to convert * \param[out] size the size of the converted result */ ldns_status ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *size); /** * Allocates an array of uint8_t at dest, and puts the wireformat of the * given rr in that array. The result_size value contains the * length of the array, if it succeeds, and 0 otherwise (in which case * the function also returns NULL) * * If the section argument is LDNS_SECTION_QUESTION, data like ttl and rdata * are not put into the result * * \param[out] dest pointer to the array of bytes to be created * \param[in] rr the rr to convert * \param[in] section the rr section, determines how the rr is written. * \param[out] size the size of the converted result */ ldns_status ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *size); /** * Allocates an array of uint8_t at dest, and puts the wireformat of the * given packet in that array. The result_size value contains the * length of the array, if it succeeds, and 0 otherwise (in which case * the function also returns NULL) */ ldns_status ldns_pkt2wire(uint8_t **dest, const ldns_pkt *p, size_t *size); #ifdef __cplusplus } #endif #endif /* LDNS_HOST2WIRE_H */ Net-LDNS-0.75/include/ldns/keys.h000644 000770 000024 00000041564 12471046240 017035 0ustar00calledstaff000000 000000 /* * * keys.h * * priv key definitions * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ /** * \file * * Addendum to \ref dnssec.h, this module contains key and algorithm definitions and functions. */ #ifndef LDNS_KEYS_H #define LDNS_KEYS_H #include #if LDNS_BUILD_CONFIG_HAVE_SSL #include #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ #include #include #ifdef __cplusplus extern "C" { #endif extern ldns_lookup_table ldns_signing_algorithms[]; #define LDNS_KEY_ZONE_KEY 0x0100 /* rfc 4034 */ #define LDNS_KEY_SEP_KEY 0x0001 /* rfc 4034 */ #define LDNS_KEY_REVOKE_KEY 0x0080 /* rfc 5011 */ /** * Algorithms used in dns */ enum ldns_enum_algorithm { LDNS_RSAMD5 = 1, /* RFC 4034,4035 */ LDNS_DH = 2, LDNS_DSA = 3, LDNS_ECC = 4, LDNS_RSASHA1 = 5, LDNS_DSA_NSEC3 = 6, LDNS_RSASHA1_NSEC3 = 7, LDNS_RSASHA256 = 8, /* RFC 5702 */ LDNS_RSASHA512 = 10, /* RFC 5702 */ LDNS_ECC_GOST = 12, /* RFC 5933 */ LDNS_ECDSAP256SHA256 = 13, /* RFC 6605 */ LDNS_ECDSAP384SHA384 = 14, /* RFC 6605 */ LDNS_INDIRECT = 252, LDNS_PRIVATEDNS = 253, LDNS_PRIVATEOID = 254 }; typedef enum ldns_enum_algorithm ldns_algorithm; /** * Hashing algorithms used in the DS record */ enum ldns_enum_hash { LDNS_SHA1 = 1, /* RFC 4034 */ LDNS_SHA256 = 2, /* RFC 4509 */ LDNS_HASH_GOST = 3, /* RFC 5933 */ LDNS_SHA384 = 4 /* RFC 6605 */ }; typedef enum ldns_enum_hash ldns_hash; /** * Algorithms used in dns for signing */ enum ldns_enum_signing_algorithm { LDNS_SIGN_RSAMD5 = LDNS_RSAMD5, LDNS_SIGN_RSASHA1 = LDNS_RSASHA1, LDNS_SIGN_DSA = LDNS_DSA, LDNS_SIGN_RSASHA1_NSEC3 = LDNS_RSASHA1_NSEC3, LDNS_SIGN_RSASHA256 = LDNS_RSASHA256, LDNS_SIGN_RSASHA512 = LDNS_RSASHA512, LDNS_SIGN_DSA_NSEC3 = LDNS_DSA_NSEC3, LDNS_SIGN_ECC_GOST = LDNS_ECC_GOST, LDNS_SIGN_ECDSAP256SHA256 = LDNS_ECDSAP256SHA256, LDNS_SIGN_ECDSAP384SHA384 = LDNS_ECDSAP384SHA384, LDNS_SIGN_HMACMD5 = 157, /* not official! This type is for TSIG, not DNSSEC */ LDNS_SIGN_HMACSHA1 = 158, /* not official! This type is for TSIG, not DNSSEC */ LDNS_SIGN_HMACSHA256 = 159 /* ditto */ }; typedef enum ldns_enum_signing_algorithm ldns_signing_algorithm; /** * General key structure, can contain all types of keys that * are used in DNSSEC. Mostly used to store private keys, since * public keys can also be stored in a \ref ldns_rr with type * \ref LDNS_RR_TYPE_DNSKEY. * * This structure can also store some variables that influence the * signatures generated by signing with this key, for instance the * inception date. */ struct ldns_struct_key { ldns_signing_algorithm _alg; /** Whether to use this key when signing */ bool _use; /** Storage pointers for the types of keys supported */ /* TODO remove unions? */ struct { #if LDNS_BUILD_CONFIG_HAVE_SSL #ifndef S_SPLINT_S /* The key can be an OpenSSL EVP Key */ EVP_PKEY *key; #endif #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ /** * The key can be an HMAC key */ struct { unsigned char *key; size_t size; } hmac; /** the key structure can also just point to some external * key data */ void *external_key; } _key; /** Depending on the key we can have extra data */ union { /** Some values that influence generated signatures */ struct { /** The TTL of the rrset that is currently signed */ uint32_t orig_ttl; /** The inception date of signatures made with this key. */ uint32_t inception; /** The expiration date of signatures made with this key. */ uint32_t expiration; /** The keytag of this key. */ uint16_t keytag; /** The dnssec key flags as specified in RFC4035, like ZSK and KSK */ uint16_t flags; } dnssec; } _extra; /** Owner name of the key */ ldns_rdf *_pubkey_owner; }; typedef struct ldns_struct_key ldns_key; /** * Same as rr_list, but now for keys */ struct ldns_struct_key_list { size_t _key_count; ldns_key **_keys; }; typedef struct ldns_struct_key_list ldns_key_list; /** * Creates a new empty key list * \return a new ldns_key_list structure pointer */ ldns_key_list *ldns_key_list_new(void); /** * Creates a new empty key structure * \return a new ldns_key * structure */ ldns_key *ldns_key_new(void); /** * Creates a new key based on the algorithm * * \param[in] a The algorithm to use * \param[in] size the number of bytes for the keysize * \return a new ldns_key structure with the key */ ldns_key *ldns_key_new_frm_algorithm(ldns_signing_algorithm a, uint16_t size); /** * Creates a new priv key based on the * contents of the file pointed by fp. * * The file should be in Private-key-format v1.x. * * \param[out] k the new ldns_key structure * \param[in] fp the file pointer to use * \return an error or LDNS_STATUS_OK */ ldns_status ldns_key_new_frm_fp(ldns_key **k, FILE *fp); /** * Creates a new private key based on the * contents of the file pointed by fp * * The file should be in Private-key-format v1.x. * * \param[out] k the new ldns_key structure * \param[in] fp the file pointer to use * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes) * \return an error or LDNS_STATUS_OK */ ldns_status ldns_key_new_frm_fp_l(ldns_key **k, FILE *fp, int *line_nr); #if LDNS_BUILD_CONFIG_HAVE_SSL /** * Read the key with the given id from the given engine and store it * in the given ldns_key structure. The algorithm type is set */ ldns_status ldns_key_new_frm_engine(ldns_key **key, ENGINE *e, char *key_id, ldns_algorithm); /** * frm_fp helper function. This function parses the * remainder of the (RSA) priv. key file generated from bind9 * \param[in] fp the file to parse * \return NULL on failure otherwise a RSA structure */ RSA *ldns_key_new_frm_fp_rsa(FILE *fp); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ #if LDNS_BUILD_CONFIG_HAVE_SSL /** * frm_fp helper function. This function parses the * remainder of the (RSA) priv. key file generated from bind9 * \param[in] fp the file to parse * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes) * \return NULL on failure otherwise a RSA structure */ RSA *ldns_key_new_frm_fp_rsa_l(FILE *fp, int *line_nr); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ #if LDNS_BUILD_CONFIG_HAVE_SSL /** * frm_fp helper function. This function parses the * remainder of the (DSA) priv. key file * \param[in] fp the file to parse * \return NULL on failure otherwise a RSA structure */ DSA *ldns_key_new_frm_fp_dsa(FILE *fp); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ #if LDNS_BUILD_CONFIG_HAVE_SSL /** * frm_fp helper function. This function parses the * remainder of the (DSA) priv. key file * \param[in] fp the file to parse * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes) * \return NULL on failure otherwise a RSA structure */ DSA *ldns_key_new_frm_fp_dsa_l(FILE *fp, int *line_nr); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ #if LDNS_BUILD_CONFIG_HAVE_SSL /** * frm_fp helper function. This function parses the * remainder of the (HMAC-MD5) key file * This function allocated a buffer that needs to be freed * \param[in] fp the file to parse * \param[out] hmac_size the number of bits in the resulting buffer * \return NULL on failure otherwise a newly allocated char buffer */ unsigned char *ldns_key_new_frm_fp_hmac(FILE *fp, size_t *hmac_size); #endif #if LDNS_BUILD_CONFIG_HAVE_SSL /** * frm_fp helper function. This function parses the * remainder of the (HMAC-MD5) key file * This function allocated a buffer that needs to be freed * \param[in] fp the file to parse * \param[in] line_nr pointer to an integer containing the current line number (for error reporting purposes) * \param[out] hmac_size the number of bits in the resulting buffer * \return NULL on failure otherwise a newly allocated char buffer */ unsigned char *ldns_key_new_frm_fp_hmac_l(FILE *fp, int *line_nr, size_t *hmac_size); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ /* acces write functions */ /** * Set the key's algorithm * \param[in] k the key * \param[in] l the algorithm */ void ldns_key_set_algorithm(ldns_key *k, ldns_signing_algorithm l); #if LDNS_BUILD_CONFIG_HAVE_SSL /** * Set the key's evp key * \param[in] k the key * \param[in] e the evp key */ void ldns_key_set_evp_key(ldns_key *k, EVP_PKEY *e); /** * Set the key's rsa data. * The rsa data should be freed by the user. * \param[in] k the key * \param[in] r the rsa data */ void ldns_key_set_rsa_key(ldns_key *k, RSA *r); /** * Set the key's dsa data * The dsa data should be freed by the user. * \param[in] k the key * \param[in] d the dsa data */ void ldns_key_set_dsa_key(ldns_key *k, DSA *d); /** * Assign the key's rsa data * The rsa data will be freed automatically when the key is freed. * \param[in] k the key * \param[in] r the rsa data */ void ldns_key_assign_rsa_key(ldns_key *k, RSA *r); /** * Assign the key's dsa data * The dsa data will be freed automatically when the key is freed. * \param[in] k the key * \param[in] d the dsa data */ void ldns_key_assign_dsa_key(ldns_key *k, DSA *d); /** * Get the PKEY id for GOST, loads GOST into openssl as a side effect. * Only available if GOST is compiled into the library and openssl. * \return the gost id for EVP_CTX creation. */ int ldns_key_EVP_load_gost_id(void); /** Release the engine reference held for the GOST engine. */ void ldns_key_EVP_unload_gost(void); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ /** * Set the key's hmac data * \param[in] k the key * \param[in] hmac the raw key data */ void ldns_key_set_hmac_key(ldns_key *k, unsigned char *hmac); /** * Set the key id data. This is used if the key points to * some externally stored key data * * Only the pointer is set, the data there is not copied, * and must be freed manually; ldns_key_deep_free() does * *not* free this data * \param[in] key the key * \param[in] external_key key id data */ void ldns_key_set_external_key(ldns_key *key, void *external_key); /** * Set the key's hmac size * \param[in] k the key * \param[in] hmac_size the size of the hmac data */ void ldns_key_set_hmac_size(ldns_key *k, size_t hmac_size); /** * Set the key's original ttl * \param[in] k the key * \param[in] t the ttl */ void ldns_key_set_origttl(ldns_key *k, uint32_t t); /** * Set the key's inception date (seconds after epoch) * \param[in] k the key * \param[in] i the inception */ void ldns_key_set_inception(ldns_key *k, uint32_t i); /** * Set the key's expiration date (seconds after epoch) * \param[in] k the key * \param[in] e the expiration */ void ldns_key_set_expiration(ldns_key *k, uint32_t e); /** * Set the key's pubkey owner * \param[in] k the key * \param[in] r the owner */ void ldns_key_set_pubkey_owner(ldns_key *k, ldns_rdf *r); /** * Set the key's key tag * \param[in] k the key * \param[in] tag the keytag */ void ldns_key_set_keytag(ldns_key *k, uint16_t tag); /** * Set the key's flags * \param[in] k the key * \param[in] flags the flags */ void ldns_key_set_flags(ldns_key *k, uint16_t flags); /** * Set the keylist's key count to count * \param[in] key the key * \param[in] count the cuont */ void ldns_key_list_set_key_count(ldns_key_list *key, size_t count); /** * pushes a key to a keylist * \param[in] key_list the key_list to push to * \param[in] key the key to push * \return false on error, otherwise true */ bool ldns_key_list_push_key(ldns_key_list *key_list, ldns_key *key); /** * returns the number of keys in the key list * \param[in] key_list the key_list * \return the numbers of keys in the list */ size_t ldns_key_list_key_count(const ldns_key_list *key_list); /** * returns a pointer to the key in the list at the given position * \param[in] key the key * \param[in] nr the position in the list * \return the key */ ldns_key *ldns_key_list_key(const ldns_key_list *key, size_t nr); #if LDNS_BUILD_CONFIG_HAVE_SSL /** * returns the (openssl) RSA struct contained in the key * \param[in] k the key to look in * \return the RSA * structure in the key */ RSA *ldns_key_rsa_key(const ldns_key *k); /** * returns the (openssl) EVP struct contained in the key * \param[in] k the key to look in * \return the RSA * structure in the key */ EVP_PKEY *ldns_key_evp_key(const ldns_key *k); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ /** * returns the (openssl) DSA struct contained in the key */ #if LDNS_BUILD_CONFIG_HAVE_SSL DSA *ldns_key_dsa_key(const ldns_key *k); #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */ /** * return the signing alg of the key * \param[in] k the key * \return the algorithm */ ldns_signing_algorithm ldns_key_algorithm(const ldns_key *k); /** * set the use flag * \param[in] k the key * \param[in] v the boolean value to set the _use field to */ void ldns_key_set_use(ldns_key *k, bool v); /** * return the use flag * \param[in] k the key * \return the boolean value of the _use field */ bool ldns_key_use(const ldns_key *k); /** * return the hmac key data * \param[in] k the key * \return the hmac key data */ unsigned char *ldns_key_hmac_key(const ldns_key *k); /** * return the key id key data * \param[in] k the key * \return the key id data */ void *ldns_key_external_key(const ldns_key *k); /** * return the hmac key size * \param[in] k the key * \return the hmac key size */ size_t ldns_key_hmac_size(const ldns_key *k); /** * return the original ttl of the key * \param[in] k the key * \return the original ttl */ uint32_t ldns_key_origttl(const ldns_key *k); /** * return the key's inception date * \param[in] k the key * \return the inception date */ uint32_t ldns_key_inception(const ldns_key *k); /** * return the key's expiration date * \param[in] k the key * \return the experiration date */ uint32_t ldns_key_expiration(const ldns_key *k); /** * return the keytag * \param[in] k the key * \return the keytag */ uint16_t ldns_key_keytag(const ldns_key *k); /** * return the public key's owner * \param[in] k the key * \return the owner */ ldns_rdf *ldns_key_pubkey_owner(const ldns_key *k); /** * Set the 'use' flag for all keys in the list * \param[in] keys The key_list * \param[in] v The value to set the use flags to */ void ldns_key_list_set_use(ldns_key_list *keys, bool v); /** * return the flag of the key * \param[in] k the key * \return the flag */ uint16_t ldns_key_flags(const ldns_key *k); /** * pops the last rr from a keylist * \param[in] key_list the rr_list to pop from * \return NULL if nothing to pop. Otherwise the popped RR */ ldns_key *ldns_key_list_pop_key(ldns_key_list *key_list); /** * converts a ldns_key to a public key rr * If the key data exists at an external point, the corresponding * rdata field must still be added with ldns_rr_rdf_push() to the * result rr of this function * * \param[in] k the ldns_key to convert * \return ldns_rr representation of the key */ ldns_rr *ldns_key2rr(const ldns_key *k); /** * print a private key to the file ouput * * \param[in] output the FILE descriptor where to print to * \param[in] k the ldns_key to print */ void ldns_key_print(FILE *output, const ldns_key *k); /** * frees a key structure, but not its internal data structures * * \param[in] key the key object to free */ void ldns_key_free(ldns_key *key); /** * frees a key structure and all its internal data structures, except * the data set by ldns_key_set_external_key() * * \param[in] key the key object to free */ void ldns_key_deep_free(ldns_key *key); /** * Frees a key list structure * \param[in] key_list the key list object to free */ void ldns_key_list_free(ldns_key_list *key_list); /** * Instantiates a DNSKEY or DS RR from file. * \param[in] filename the file to read the record from * \return the corresponding RR, or NULL if the parsing failed */ ldns_rr * ldns_read_anchor_file(const char *filename); /** * Returns the 'default base name' for key files; * IE. K\+\+\ * (without the .key or .private) * The memory for this is allocated by this function, * and should be freed by the caller * * \param[in] key the key to get the file name from * \returns A string containing the file base name */ char *ldns_key_get_file_base_name(ldns_key *key); /** * See if a key algorithm is supported * \param[in] algo the signing algorithm number. * \returns true if supported. */ int ldns_key_algo_supported(int algo); /** * Get signing algorithm by name. Comparison is case insensitive. * \param[in] name string with the name. * \returns 0 on parse failure or the algorithm number. */ ldns_signing_algorithm ldns_get_signing_algorithm_by_name(const char* name); #ifdef __cplusplus } #endif #endif /* LDNS_KEYS_H */ Net-LDNS-0.75/include/ldns/ldns.h000644 000770 000024 00000011042 12471046240 017006 0ustar00calledstaff000000 000000 /* * dns.h -- defines for the Domain Name System * * Copyright (c) 2005-2008, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * This library was created by: * Jelte Jansen, Erik Rozendaal and Miek Gieben * * A bunch of defines that are used in the DNS. */ /** \mainpage LDNS Documentation \section introduction Introduction The goal of ldns is to simplify DNS programming, it supports recent RFCs like the DNSSEC documents, and allow developers to easily create software conforming to current RFCs, and experimental software for current Internet drafts. A secondary benefit of using ldns is speed, because ldns is written in C, and although it is not optimized for performance, it should be a lot faster than Perl. The first main tool to use ldns is Drill, from which part of the library was derived. From version 1.0.0 on, drill is included in the ldns release and will not be distributed separately anymore. The library also includes some other examples and tools to show how it can be used. These can be found in the examples/ directory in the tarball. ldns depends on OpenSSL for it's cryptographic functions. Feature list - Transparent IPv4 and IPv6 support (overridable if necessary), - TSIG support, - DNSSEC support; signing and verification, - small size, - online documentation as well as manual pages. If you want to send us patches please use the code from git. \section using_ldns Using ldns Almost all interaction between an application and ldns goes through the ldns data structures (\ref ldns_rr, \ref ldns_pkt, etc.). These are input or output to the functions of ldns. For example, \ref ldns_zone_new_frm_fp reads a zone from a \c FILE pointer, and returns an \ref ldns_zone structure. Let's use Drill as an example. Drill is a tool much like dig, whose most basic function is to send 1 query to a nameserver and print the response. To be able to do this, drill uses the resolver module of ldns, which acts as a stub resolver. The resolver module uses the net module to actually send the query that drill requested. It then uses the wire2host module to translate the response and place it in ldns' internal structures. These are passed back to drill, which then uses the host2str module to print the response in presentation format. \section gettingstarted Getting Started See the \ref design page for a very high level description of the design choices made for ldns. For an overview of the functions and types ldns provides, you can check out the \ref ldns ldns header file descriptions. If you want to see some libdns action, you can read our tutorials: - \ref tutorial1_mx - \ref tutorial2_zone - \ref tutorial3_signzone Or you can just use the menu above to browse through the API docs.
\image html LogoInGradientBar2-y100.png
*/ /** * \file ldns.h * * Including this file will include all ldns files, and define some lookup tables. */ #ifndef LDNS_DNS_H #define LDNS_DNS_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define LDNS_IP4ADDRLEN (32/8) #define LDNS_IP6ADDRLEN (128/8) #define LDNS_PORT 53 #define LDNS_ROOT_LABEL_STR "." #define LDNS_DEFAULT_TTL 3600 /* lookup tables for standard DNS stuff */ /** Taken from RFC 2538, section 2.1. */ extern ldns_lookup_table ldns_certificate_types[]; /** Taken from RFC 2535, section 7. */ extern ldns_lookup_table ldns_algorithms[]; /** Taken from RFC 2538. */ extern ldns_lookup_table ldns_cert_algorithms[]; /** rr types */ extern ldns_lookup_table ldns_rr_classes[]; /** Response codes */ extern ldns_lookup_table ldns_rcodes[]; /** Operation codes */ extern ldns_lookup_table ldns_opcodes[]; /** EDNS flags */ extern ldns_lookup_table ldns_edns_flags[]; #ifdef __cplusplus } #endif #endif /* LDNS_DNS_H */ Net-LDNS-0.75/include/ldns/net.h000644 000770 000024 00000015711 12471046240 016643 0ustar00calledstaff000000 000000 /* * net.h * * DNS Resolver definitions * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ #ifndef LDNS_NET_H #define LDNS_NET_H #include #include #ifdef __cplusplus extern "C" { #endif #define LDNS_DEFAULT_TIMEOUT_SEC 5 #define LDNS_DEFAULT_TIMEOUT_USEC 0 /** * \file * * Contains functions to send and receive packets over a network. */ /** * Sends a buffer to an ip using udp and return the respons as a ldns_pkt * \param[in] qbin the ldns_buffer to be send * \param[in] to the ip addr to send to * \param[in] tolen length of the ip addr * \param[in] timeout the timeout value for the network * \param[out] answersize size of the packet * \param[out] result packet with the answer * \return status */ ldns_status ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout, size_t *answersize); /** * Send an udp query and don't wait for an answer but return * the socket * \param[in] qbin the ldns_buffer to be send * \param[in] to the ip addr to send to * \param[in] tolen length of the ip addr * \param[in] timeout *unused*, was the timeout value for the network * \return the socket used */ int ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout); /** * Send an tcp query and don't wait for an answer but return * the socket * \param[in] qbin the ldns_buffer to be send * \param[in] to the ip addr to send to * \param[in] tolen length of the ip addr * \param[in] timeout the timeout value for the connect attempt * \return the socket used */ int ldns_tcp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout); /** * Sends a buffer to an ip using tcp and return the respons as a ldns_pkt * \param[in] qbin the ldns_buffer to be send * \param[in] qbin the ldns_buffer to be send * \param[in] to the ip addr to send to * \param[in] tolen length of the ip addr * \param[in] timeout the timeout value for the network * \param[out] answersize size of the packet * \param[out] result packet with the answer * \return status */ ldns_status ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout, size_t *answersize); /** * Sends ptk to the nameserver at the resolver object. Returns the data * as a ldns_pkt * * \param[out] pkt packet received from the nameserver * \param[in] r the resolver to use * \param[in] query_pkt the query to send * \return status */ ldns_status ldns_send(ldns_pkt **pkt, ldns_resolver *r, const ldns_pkt *query_pkt); /** * Sends and ldns_buffer (presumably containing a packet to the nameserver at the resolver object. Returns the data * as a ldns_pkt * * \param[out] pkt packet received from the nameserver * \param[in] r the resolver to use * \param[in] qb the buffer to send * \param[in] tsig_mac the tsig MAC to authenticate the response with (NULL to do no TSIG authentication) * \return status */ ldns_status ldns_send_buffer(ldns_pkt **pkt, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac); /** * Create a tcp socket to the specified address * \param[in] to ip and family * \param[in] tolen length of to * \param[in] timeout timeout for the connect attempt * \return a socket descriptor */ int ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout); /** * Create a udp socket to the specified address * \param[in] to ip and family * \param[in] timeout *unused*, was timeout for the socket * \return a socket descriptor */ int ldns_udp_connect(const struct sockaddr_storage *to, struct timeval timeout); /** * send a query via tcp to a server. Don't want for the answer * * \param[in] qbin the buffer to send * \param[in] sockfd the socket to use * \param[in] to which ip to send it * \param[in] tolen socketlen * \return number of bytes sent */ ssize_t ldns_tcp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen); /** * send a query via udp to a server. Don;t want for the answer * * \param[in] qbin the buffer to send * \param[in] sockfd the socket to use * \param[in] to which ip to send it * \param[in] tolen socketlen * \return number of bytes sent */ ssize_t ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen); /** * Gives back a raw packet from the wire and reads the header data from the given * socket. Allocates the data (of size size) itself, so don't forget to free * * \param[in] sockfd the socket to read from * \param[out] size the number of bytes that are read * \param[in] timeout the time allowed between packets. * \return the data read */ uint8_t *ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout); /** * This routine may block. Use ldns_tcp_read_wire_timeout, it checks timeouts. * Gives back a raw packet from the wire and reads the header data from the given * socket. Allocates the data (of size size) itself, so don't forget to free * * \param[in] sockfd the socket to read from * \param[out] size the number of bytes that are read * \return the data read */ uint8_t *ldns_tcp_read_wire(int sockfd, size_t *size); /** * Gives back a raw packet from the wire and reads the header data from the given * socket. Allocates the data (of size size) itself, so don't forget to free * * \param[in] sockfd the socket to read from * \param[in] fr the address of the client (if applicable) * \param[in] *frlen the lenght of the client's addr (if applicable) * \param[out] size the number of bytes that are read * \return the data read */ uint8_t *ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *fr, socklen_t *frlen); /** * returns the native sockaddr representation from the rdf. * \param[in] rd the ldns_rdf to operate on * \param[in] port what port to use. 0 means; use default (53) * \param[out] size what is the size of the sockaddr_storage * \return struct sockaddr* the address in the format so other * functions can use it (sendto) */ struct sockaddr_storage * ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, uint16_t port, size_t *size); /** * returns an rdf with the sockaddr info. works for ip4 and ip6 * \param[in] sock the struct sockaddr_storage to convert * \param[in] port what port was used. When NULL this is not set * \return ldns_rdf* wth the address */ ldns_rdf * ldns_sockaddr_storage2rdf(struct sockaddr_storage *sock, uint16_t *port); /** * Prepares the resolver for an axfr query * The query is sent and the answers can be read with ldns_axfr_next * \param[in] resolver the resolver to use * \param[in] domain the domain to exfr * \param[in] c the class to use * \return ldns_status the status of the transfer */ ldns_status ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class c); #ifdef __cplusplus } #endif #endif /* LDNS_NET_H */ Net-LDNS-0.75/include/ldns/packet.h000644 000770 000024 00000062164 12471046240 017330 0ustar00calledstaff000000 000000 /* * packet.h * * DNS packet definitions * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ /** * \file * * Contains the definition of ldns_pkt and its parts, as well * as functions to manipulate those. */ #ifndef LDNS_PACKET_H #define LDNS_PACKET_H #define LDNS_MAX_PACKETLEN 65535 /* allow flags to be given to mk_query */ #define LDNS_QR 1 /* QueRy - query flag */ #define LDNS_AA 2 /* Authoritative Answer - server flag */ #define LDNS_TC 4 /* TrunCated - server flag */ #define LDNS_RD 8 /* Recursion Desired - query flag */ #define LDNS_CD 16 /* Checking Disabled - query flag */ #define LDNS_RA 32 /* Recursion Available - server flag */ #define LDNS_AD 64 /* Authenticated Data - server flag */ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* opcodes for pkt's */ enum ldns_enum_pkt_opcode { LDNS_PACKET_QUERY = 0, LDNS_PACKET_IQUERY = 1, LDNS_PACKET_STATUS = 2, /* there is no 3?? DNS is weird */ LDNS_PACKET_NOTIFY = 4, LDNS_PACKET_UPDATE = 5 }; typedef enum ldns_enum_pkt_opcode ldns_pkt_opcode; /* rcodes for pkts */ enum ldns_enum_pkt_rcode { LDNS_RCODE_NOERROR = 0, LDNS_RCODE_FORMERR = 1, LDNS_RCODE_SERVFAIL = 2, LDNS_RCODE_NXDOMAIN = 3, LDNS_RCODE_NOTIMPL = 4, LDNS_RCODE_REFUSED = 5, LDNS_RCODE_YXDOMAIN = 6, LDNS_RCODE_YXRRSET = 7, LDNS_RCODE_NXRRSET = 8, LDNS_RCODE_NOTAUTH = 9, LDNS_RCODE_NOTZONE = 10 }; typedef enum ldns_enum_pkt_rcode ldns_pkt_rcode; /** * Header of a dns packet * * Contains the information about the packet itself, as specified in RFC1035
4.1.1. Header section format

The header contains the following fields:

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      ID                       |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    QDCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ANCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    NSCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ARCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

where:

ID              A 16 bit identifier assigned by the program that
                generates any kind of query.  This identifier is copied
                the corresponding reply and can be used by the requester
                to match up replies to outstanding queries.

QR              A one bit field that specifies whether this message is a
                query (0), or a response (1).

OPCODE          A four bit field that specifies kind of query in this
                message.  This value is set by the originator of a query
                and copied into the response.  The values are:

                0               a standard query (QUERY)

                1               an inverse query (IQUERY)

                2               a server status request (STATUS)

                3-15            reserved for future use

AA              Authoritative Answer - this bit is valid in responses,
                and specifies that the responding name server is an
                authority for the domain name in question section.

                Note that the contents of the answer section may have
                multiple owner names because of aliases.  The AA bit

                corresponds to the name which matches the query name, or
                the first owner name in the answer section.

TC              TrunCation - specifies that this message was truncated
                due to length greater than that permitted on the
                transmission channel.

RD              Recursion Desired - this bit may be set in a query and
                is copied into the response.  If RD is set, it directs
                the name server to pursue the query recursively.
                Recursive query support is optional.

RA              Recursion Available - this be is set or cleared in a
                response, and denotes whether recursive query support is
                available in the name server.

Z               Reserved for future use.  Must be zero in all queries
                and responses.

RCODE           Response code - this 4 bit field is set as part of
                responses.  The values have the following
                interpretation:

                0               No error condition

                1               Format error - The name server was
                                unable to interpret the query.

                2               Server failure - The name server was
                                unable to process this query due to a
                                problem with the name server.

                3               Name Error - Meaningful only for
                                responses from an authoritative name
                                server, this code signifies that the
                                domain name referenced in the query does
                                not exist.

                4               Not Implemented - The name server does
                                not support the requested kind of query.

                5               Refused - The name server refuses to
                                perform the specified operation for
                                policy reasons.  For example, a name
                                server may not wish to provide the
                                information to the particular requester,
                                or a name server may not wish to perform
                                a particular operation (e.g., zone

                                transfer) for particular data.

                6-15            Reserved for future use.

QDCOUNT         an unsigned 16 bit integer specifying the number of
                entries in the question section.

ANCOUNT         an unsigned 16 bit integer specifying the number of
                resource records in the answer section.

NSCOUNT         an unsigned 16 bit integer specifying the number of name
                server resource records in the authority records
                section.

ARCOUNT         an unsigned 16 bit integer specifying the number of
                resource records in the additional records section.

*/ struct ldns_struct_hdr { /** Id of a packet */ uint16_t _id; /** Query bit (0=query, 1=answer) */ bool _qr; /** Authoritative answer */ bool _aa; /** Packet truncated */ bool _tc; /** Recursion desired */ bool _rd; /** Checking disabled */ bool _cd; /** Recursion available */ bool _ra; /** Authentic data */ bool _ad; /** Query type */ ldns_pkt_opcode _opcode; /* XXX 8 bits? */ /** Response code */ uint8_t _rcode; /** question sec */ uint16_t _qdcount; /** answer sec */ uint16_t _ancount; /** auth sec */ uint16_t _nscount; /** add sec */ uint16_t _arcount; }; typedef struct ldns_struct_hdr ldns_hdr; /** * DNS packet * * This structure contains a complete DNS packet (either a query or an answer) * * It is the complete representation of what you actually send to a * nameserver, and what it sends back (assuming you are the client here). */ struct ldns_struct_pkt { /** Header section */ ldns_hdr *_header; /* extra items needed in a packet */ /** The size of the wire format of the packet in octets */ ldns_rdf *_answerfrom; /** Timestamp of the time the packet was sent or created */ struct timeval timestamp; /** The duration of the query this packet is an answer to */ uint32_t _querytime; /** The size of the wire format of the packet in octets */ size_t _size; /** Optional tsig rr */ ldns_rr *_tsig_rr; /** EDNS0 available buffer size, see RFC2671 */ uint16_t _edns_udp_size; /** EDNS0 Extended rcode */ uint8_t _edns_extended_rcode; /** EDNS Version */ uint8_t _edns_version; /* OPT pseudo-RR presence flag */ uint8_t _edns_present; /** Reserved EDNS data bits */ uint16_t _edns_z; /** Arbitrary EDNS rdata */ ldns_rdf *_edns_data; /** Question section */ ldns_rr_list *_question; /** Answer section */ ldns_rr_list *_answer; /** Authority section */ ldns_rr_list *_authority; /** Additional section */ ldns_rr_list *_additional; }; typedef struct ldns_struct_pkt ldns_pkt; /** * The sections of a packet */ enum ldns_enum_pkt_section { LDNS_SECTION_QUESTION = 0, LDNS_SECTION_ANSWER = 1, LDNS_SECTION_AUTHORITY = 2, LDNS_SECTION_ADDITIONAL = 3, /** bogus section, if not interested */ LDNS_SECTION_ANY = 4, /** used to get all non-question rrs from a packet */ LDNS_SECTION_ANY_NOQUESTION = 5 }; typedef enum ldns_enum_pkt_section ldns_pkt_section; /** * The different types of packets */ enum ldns_enum_pkt_type { LDNS_PACKET_QUESTION, LDNS_PACKET_REFERRAL, LDNS_PACKET_ANSWER, LDNS_PACKET_NXDOMAIN, LDNS_PACKET_NODATA, LDNS_PACKET_UNKNOWN }; typedef enum ldns_enum_pkt_type ldns_pkt_type; /* prototypes */ /* read */ /** * Read the packet id * \param[in] p the packet * \return the packet id */ uint16_t ldns_pkt_id(const ldns_pkt *p); /** * Read the packet's qr bit * \param[in] p the packet * \return value of the bit */ bool ldns_pkt_qr(const ldns_pkt *p); /** * Read the packet's aa bit * \param[in] p the packet * \return value of the bit */ bool ldns_pkt_aa(const ldns_pkt *p); /** * Read the packet's tc bit * \param[in] p the packet * \return value of the bit */ bool ldns_pkt_tc(const ldns_pkt *p); /** * Read the packet's rd bit * \param[in] p the packet * \return value of the bit */ bool ldns_pkt_rd(const ldns_pkt *p); /** * Read the packet's cd bit * \param[in] p the packet * \return value of the bit */ bool ldns_pkt_cd(const ldns_pkt *p); /** * Read the packet's ra bit * \param[in] p the packet * \return value of the bit */ bool ldns_pkt_ra(const ldns_pkt *p); /** * Read the packet's ad bit * \param[in] p the packet * \return value of the bit */ bool ldns_pkt_ad(const ldns_pkt *p); /** * Read the packet's code * \param[in] p the packet * \return the opcode */ ldns_pkt_opcode ldns_pkt_get_opcode(const ldns_pkt *p); /** * Return the packet's respons code * \param[in] p the packet * \return the respons code */ ldns_pkt_rcode ldns_pkt_get_rcode(const ldns_pkt *p); /** * Return the packet's qd count * \param[in] p the packet * \return the qd count */ uint16_t ldns_pkt_qdcount(const ldns_pkt *p); /** * Return the packet's an count * \param[in] p the packet * \return the an count */ uint16_t ldns_pkt_ancount(const ldns_pkt *p); /** * Return the packet's ns count * \param[in] p the packet * \return the ns count */ uint16_t ldns_pkt_nscount(const ldns_pkt *p); /** * Return the packet's ar count * \param[in] p the packet * \return the ar count */ uint16_t ldns_pkt_arcount(const ldns_pkt *p); /** * Return the packet's answerfrom * \param[in] p packet * \return the name of the server */ ldns_rdf *ldns_pkt_answerfrom(const ldns_pkt *p); /** * Return the packet's timestamp * \param[in] p the packet * \return the timestamp */ struct timeval ldns_pkt_timestamp(const ldns_pkt *p); /** * Return the packet's querytime * \param[in] p the packet * \return the querytime */ uint32_t ldns_pkt_querytime(const ldns_pkt *p); /** * Return the packet's size in bytes * \param[in] p the packet * \return the size */ size_t ldns_pkt_size(const ldns_pkt *p); /** * Return the number of RRs in the given section. * Returns the sum of all RRs when LDNS_SECTION_ANY is given. * Returns the sum of all non-question RRs when LDNS_SECTION_ANY_NOQUESTION * is given. * \param[in] p the packet * \param[in] s the section * \return the number of RRs in the given section */ uint16_t ldns_pkt_section_count(const ldns_pkt *p, ldns_pkt_section s); /** * Return the packet's tsig pseudo rr's * \param[in] p the packet * \return the tsig rr */ ldns_rr *ldns_pkt_tsig(const ldns_pkt *p); /** * Return the packet's question section * \param[in] p the packet * \return the section */ ldns_rr_list *ldns_pkt_question(const ldns_pkt *p); /** * Return the packet's answer section * \param[in] p the packet * \return the section */ ldns_rr_list *ldns_pkt_answer(const ldns_pkt *p); /** * Return the packet's authority section * \param[in] p the packet * \return the section */ ldns_rr_list *ldns_pkt_authority(const ldns_pkt *p); /** * Return the packet's additional section * \param[in] p the packet * \return the section */ ldns_rr_list *ldns_pkt_additional(const ldns_pkt *p); /** * Return the packet's question, answer, authority and additional sections * concatenated, in a new rr_list clone. * \param[in] p the packet * \return the rrs */ ldns_rr_list *ldns_pkt_all(const ldns_pkt *p); /** * Return the packet's answer, authority and additional sections concatenated, * in a new rr_list clone. Like ldns_pkt_all but without the questions. * \param[in] p the packet * \return the rrs except the question rrs */ ldns_rr_list *ldns_pkt_all_noquestion(const ldns_pkt *p); /** * return all the rr_list's in the packet. Clone the lists, instead * of returning pointers. * \param[in] p the packet to look in * \param[in] s what section(s) to return * \return ldns_rr_list with the rr's or NULL if none were found */ ldns_rr_list *ldns_pkt_get_section_clone(const ldns_pkt *p, ldns_pkt_section s); /** * return all the rr with a specific name from a packet. Optionally * specify from which section in the packet * \param[in] p the packet * \param[in] r the name * \param[in] s the packet's section * \return a list with the rr's or NULL if none were found */ ldns_rr_list *ldns_pkt_rr_list_by_name(ldns_pkt *p, ldns_rdf *r, ldns_pkt_section s); /** * return all the rr with a specific type from a packet. Optionally * specify from which section in the packet * \param[in] p the packet * \param[in] t the type * \param[in] s the packet's section * \return a list with the rr's or NULL if none were found */ ldns_rr_list *ldns_pkt_rr_list_by_type(const ldns_pkt *p, ldns_rr_type t, ldns_pkt_section s); /** * return all the rr with a specific type and type from a packet. Optionally * specify from which section in the packet * \param[in] packet the packet * \param[in] ownername the name * \param[in] type the type * \param[in] sec the packet's section * \return a list with the rr's or NULL if none were found */ ldns_rr_list *ldns_pkt_rr_list_by_name_and_type(const ldns_pkt *packet, const ldns_rdf *ownername, ldns_rr_type type, ldns_pkt_section sec); /** * check to see if an rr exist in the packet * \param[in] pkt the packet to examine * \param[in] sec in which section to look * \param[in] rr the rr to look for */ bool ldns_pkt_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr); /** * sets the flags in a packet. * \param[in] pkt the packet to operate on * \param[in] flags ORed values: LDNS_QR| LDNS_AR for instance * \return true on success otherwise false */ bool ldns_pkt_set_flags(ldns_pkt *pkt, uint16_t flags); /** * Set the packet's id * \param[in] p the packet * \param[in] id the id to set */ void ldns_pkt_set_id(ldns_pkt *p, uint16_t id); /** * Set the packet's id to a random value * \param[in] p the packet */ void ldns_pkt_set_random_id(ldns_pkt *p); /** * Set the packet's qr bit * \param[in] p the packet * \param[in] b the value to set (boolean) */ void ldns_pkt_set_qr(ldns_pkt *p, bool b); /** * Set the packet's aa bit * \param[in] p the packet * \param[in] b the value to set (boolean) */ void ldns_pkt_set_aa(ldns_pkt *p, bool b); /** * Set the packet's tc bit * \param[in] p the packet * \param[in] b the value to set (boolean) */ void ldns_pkt_set_tc(ldns_pkt *p, bool b); /** * Set the packet's rd bit * \param[in] p the packet * \param[in] b the value to set (boolean) */ void ldns_pkt_set_rd(ldns_pkt *p, bool b); /** * Set the packet's cd bit * \param[in] p the packet * \param[in] b the value to set (boolean) */ void ldns_pkt_set_cd(ldns_pkt *p, bool b); /** * Set the packet's ra bit * \param[in] p the packet * \param[in] b the value to set (boolean) */ void ldns_pkt_set_ra(ldns_pkt *p, bool b); /** * Set the packet's ad bit * \param[in] p the packet * \param[in] b the value to set (boolean) */ void ldns_pkt_set_ad(ldns_pkt *p, bool b); /** * Set the packet's opcode * \param[in] p the packet * \param[in] c the opcode */ void ldns_pkt_set_opcode(ldns_pkt *p, ldns_pkt_opcode c); /** * Set the packet's respons code * \param[in] p the packet * \param[in] c the rcode */ void ldns_pkt_set_rcode(ldns_pkt *p, uint8_t c); /** * Set the packet's qd count * \param[in] p the packet * \param[in] c the count */ void ldns_pkt_set_qdcount(ldns_pkt *p, uint16_t c); /** * Set the packet's an count * \param[in] p the packet * \param[in] c the count */ void ldns_pkt_set_ancount(ldns_pkt *p, uint16_t c); /** * Set the packet's ns count * \param[in] p the packet * \param[in] c the count */ void ldns_pkt_set_nscount(ldns_pkt *p, uint16_t c); /** * Set the packet's arcount * \param[in] p the packet * \param[in] c the count */ void ldns_pkt_set_arcount(ldns_pkt *p, uint16_t c); /** * Set the packet's answering server * \param[in] p the packet * \param[in] r the address */ void ldns_pkt_set_answerfrom(ldns_pkt *p, ldns_rdf *r); /** * Set the packet's query time * \param[in] p the packet * \param[in] t the querytime in msec */ void ldns_pkt_set_querytime(ldns_pkt *p, uint32_t t); /** * Set the packet's size * \param[in] p the packet * \param[in] s the size */ void ldns_pkt_set_size(ldns_pkt *p, size_t s); /** * Set the packet's timestamp * \param[in] p the packet * \param[in] timeval the timestamp */ void ldns_pkt_set_timestamp(ldns_pkt *p, struct timeval timeval); /** * Set a packet's section count to x * \param[in] p the packet * \param[in] s the section * \param[in] x the section count */ void ldns_pkt_set_section_count(ldns_pkt *p, ldns_pkt_section s, uint16_t x); /** * Set the packet's tsig rr * \param[in] p the packet * \param[in] t the tsig rr */ void ldns_pkt_set_tsig(ldns_pkt *p, ldns_rr *t); /** * looks inside the packet to determine * what kind of packet it is, AUTH, NXDOMAIN, REFERRAL, etc. * \param[in] p the packet to examine * \return the type of packet */ ldns_pkt_type ldns_pkt_reply_type(ldns_pkt *p); /** * return the packet's edns udp size * \param[in] packet the packet * \return the size */ uint16_t ldns_pkt_edns_udp_size(const ldns_pkt *packet); /** * return the packet's edns extended rcode * \param[in] packet the packet * \return the rcode */ uint8_t ldns_pkt_edns_extended_rcode(const ldns_pkt *packet); /** * return the packet's edns version * \param[in] packet the packet * \return the version */ uint8_t ldns_pkt_edns_version(const ldns_pkt *packet); /** * return the packet's edns z value * \param[in] packet the packet * \return the z value */ uint16_t ldns_pkt_edns_z(const ldns_pkt *packet); /** * return the packet's edns data * \param[in] packet the packet * \return the data */ ldns_rdf *ldns_pkt_edns_data(const ldns_pkt *packet); /** * return the packet's edns do bit * \param[in] packet the packet * \return the bit's value */ bool ldns_pkt_edns_do(const ldns_pkt *packet); /** * Set the packet's edns do bit * \param[in] packet the packet * \param[in] value the bit's new value */ void ldns_pkt_set_edns_do(ldns_pkt *packet, bool value); /** * returns true if this packet needs and EDNS rr to be sent. * At the moment the only reason is an expected packet * size larger than 512 bytes, but for instance dnssec would * be a good reason too. * * \param[in] packet the packet to check * \return true if packet needs edns rr */ bool ldns_pkt_edns(const ldns_pkt *packet); /** * Set the packet's edns udp size * \param[in] packet the packet * \param[in] s the size */ void ldns_pkt_set_edns_udp_size(ldns_pkt *packet, uint16_t s); /** * Set the packet's edns extended rcode * \param[in] packet the packet * \param[in] c the code */ void ldns_pkt_set_edns_extended_rcode(ldns_pkt *packet, uint8_t c); /** * Set the packet's edns version * \param[in] packet the packet * \param[in] v the version */ void ldns_pkt_set_edns_version(ldns_pkt *packet, uint8_t v); /** * Set the packet's edns z value * \param[in] packet the packet * \param[in] z the value */ void ldns_pkt_set_edns_z(ldns_pkt *packet, uint16_t z); /** * Set the packet's edns data * \param[in] packet the packet * \param[in] data the data */ void ldns_pkt_set_edns_data(ldns_pkt *packet, ldns_rdf *data); /** * allocates and initializes a ldns_pkt structure. * \return pointer to the new packet */ ldns_pkt *ldns_pkt_new(void); /** * frees the packet structure and all data that it contains. * \param[in] packet The packet structure to free * \return void */ void ldns_pkt_free(ldns_pkt *packet); /** * creates a query packet for the given name, type, class. * \param[out] p the packet to be returned * \param[in] rr_name the name to query for (as string) * \param[in] rr_type the type to query for * \param[in] rr_class the class to query for * \param[in] flags packet flags * \return LDNS_STATUS_OK or a ldns_status mesg with the error */ ldns_status ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class , uint16_t flags); /** * creates an IXFR request packet for the given name, class. * adds the SOA record to the authority section. * \param[out] p the packet to be returned * \param[in] rr_name the name to query for (as string) * \param[in] rr_class the class to query for * \param[in] flags packet flags * \param[in] soa soa record to be added to the authority section * \return LDNS_STATUS_OK or a ldns_status mesg with the error */ ldns_status ldns_pkt_ixfr_request_new_frm_str(ldns_pkt **p, const char *rr_name, ldns_rr_class rr_class, uint16_t flags, ldns_rr* soa); /** * creates a packet with a query in it for the given name, type and class. * \param[in] rr_name the name to query for * \param[in] rr_type the type to query for * \param[in] rr_class the class to query for * \param[in] flags packet flags * \return ldns_pkt* a pointer to the new pkt */ ldns_pkt *ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags); /** * creates an IXFR request packet for the given name, type and class. * adds the SOA record to the authority section. * \param[in] rr_name the name to query for * \param[in] rr_class the class to query for * \param[in] flags packet flags * \param[in] soa soa record to be added to the authority section * \return ldns_pkt* a pointer to the new pkt */ ldns_pkt *ldns_pkt_ixfr_request_new(ldns_rdf *rr_name, ldns_rr_class rr_class, uint16_t flags, ldns_rr* soa); /** * clones the given packet, creating a fully allocated copy * * \param[in] pkt the packet to clone * \return ldns_pkt* pointer to the new packet */ ldns_pkt *ldns_pkt_clone(const ldns_pkt *pkt); /** * directly set the additional section * \param[in] p packet to operate on * \param[in] rr rrlist to set */ void ldns_pkt_set_additional(ldns_pkt *p, ldns_rr_list *rr); /** * directly set the answer section * \param[in] p packet to operate on * \param[in] rr rrlist to set */ void ldns_pkt_set_answer(ldns_pkt *p, ldns_rr_list *rr); /** * directly set the question section * \param[in] p packet to operate on * \param[in] rr rrlist to set */ void ldns_pkt_set_question(ldns_pkt *p, ldns_rr_list *rr); /** * directly set the auhority section * \param[in] p packet to operate on * \param[in] rr rrlist to set */ void ldns_pkt_set_authority(ldns_pkt *p, ldns_rr_list *rr); /** * push an rr on a packet * \param[in] packet packet to operate on * \param[in] section where to put it * \param[in] rr rr to push * \return a boolean which is true when the rr was added */ bool ldns_pkt_push_rr(ldns_pkt *packet, ldns_pkt_section section, ldns_rr *rr); /** * push an rr on a packet, provided the RR is not there. * \param[in] pkt packet to operate on * \param[in] sec where to put it * \param[in] rr rr to push * \return a boolean which is true when the rr was added */ bool ldns_pkt_safe_push_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr); /** * push a rr_list on a packet * \param[in] packet packet to operate on * \param[in] section where to put it * \param[in] list the rr_list to push * \return a boolean which is true when the rr was added */ bool ldns_pkt_push_rr_list(ldns_pkt *packet, ldns_pkt_section section, ldns_rr_list *list); /** * push an rr_list to a packet, provided the RRs are not already there. * \param[in] pkt packet to operate on * \param[in] sec where to put it * \param[in] list the rr_list to push * \return a boolean which is true when the rr was added */ bool ldns_pkt_safe_push_rr_list(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr_list *list); /** * check if a packet is empty * \param[in] p packet * \return true: empty, false: not empty */ bool ldns_pkt_empty(ldns_pkt *p); #ifdef __cplusplus } #endif #endif /* LDNS_PACKET_H */ Net-LDNS-0.75/include/ldns/parse.h000644 000770 000024 00000012765 12471046240 017175 0ustar00calledstaff000000 000000 /* * parse.h * * a Net::DNS like library for C * LibDNS Team @ NLnet Labs * (c) NLnet Labs, 2005-2006 * See the file LICENSE for the license */ #ifndef LDNS_PARSE_H #define LDNS_PARSE_H #include #include #ifdef __cplusplus extern "C" { #endif #define LDNS_PARSE_SKIP_SPACE "\f\n\r\v" #define LDNS_PARSE_NORMAL " \f\n\r\t\v" #define LDNS_PARSE_NO_NL " \t" #define LDNS_MAX_LINELEN 10230 #define LDNS_MAX_KEYWORDLEN 32 /** * \file * * Contains some low-level parsing functions, mostly used in the _frm_str * family of functions. */ /** * different type of directives in zone files * We now deal with $TTL, $ORIGIN and $INCLUDE. * The latter is not implemented in ldns (yet) */ enum ldns_enum_directive { LDNS_DIR_TTL, LDNS_DIR_ORIGIN, LDNS_DIR_INCLUDE }; typedef enum ldns_enum_directive ldns_directive; /** * returns a token/char from the stream F. * This function deals with ( and ) in the stream, * and ignores them when encountered * \param[in] *f the file to read from * \param[out] *token the read token is put here * \param[in] *delim chars at which the parsing should stop * \param[in] *limit how much to read. If 0 the builtin maximum is used * \return 0 on error of EOF of the stream F. Otherwise return the length of what is read */ ssize_t ldns_fget_token(FILE *f, char *token, const char *delim, size_t limit); /** * returns a token/char from the stream F. * This function deals with ( and ) in the stream, * and ignores when it finds them. * \param[in] *f the file to read from * \param[out] *token the token is put here * \param[in] *delim chars at which the parsing should stop * \param[in] *limit how much to read. If 0 use builtin maximum * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes) * \return 0 on error of EOF of F otherwise return the length of what is read */ ssize_t ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr); /** * returns a token/char from the buffer b. * This function deals with ( and ) in the buffer, * and ignores when it finds them. * \param[in] *b the buffer to read from * \param[out] *token the token is put here * \param[in] *delim chars at which the parsing should stop * \param[in] *limit how much to read. If 0 the builtin maximum is used * \returns 0 on error of EOF of b. Otherwise return the length of what is read */ ssize_t ldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t limit); /* * searches for keyword and delim in a file. Gives everything back * after the keyword + k_del until we hit d_del * \param[in] f file pointer to read from * \param[in] keyword keyword to look for * \param[in] k_del keyword delimeter * \param[out] data the data found * \param[in] d_del the data delimeter * \param[in] data_limit maximum size the the data buffer * \return the number of character read */ ssize_t ldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit); /* * searches for keyword and delim. Gives everything back * after the keyword + k_del until we hit d_del * \param[in] f file pointer to read from * \param[in] keyword keyword to look for * \param[in] k_del keyword delimeter * \param[out] data the data found * \param[in] d_del the data delimeter * \param[in] data_limit maximum size the the data buffer * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes) * \return the number of character read */ ssize_t ldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit, int *line_nr); /* * searches for keyword and delim in a buffer. Gives everything back * after the keyword + k_del until we hit d_del * \param[in] b buffer pointer to read from * \param[in] keyword keyword to look for * \param[in] k_del keyword delimeter * \param[out] data the data found * \param[in] d_del the data delimeter * \param[in] data_limit maximum size the the data buffer * \return the number of character read */ ssize_t ldns_bget_keyword_data(ldns_buffer *b, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit); /** * returns the next character from a buffer. Advances the position pointer with 1. * When end of buffer is reached returns EOF. This is the buffer's equivalent * for getc(). * \param[in] *buffer buffer to read from * \return EOF on failure otherwise return the character */ int ldns_bgetc(ldns_buffer *buffer); /** * skips all of the characters in the given string in the buffer, moving * the position to the first character that is not in *s. * \param[in] *buffer buffer to use * \param[in] *s characters to skip * \return void */ void ldns_bskipcs(ldns_buffer *buffer, const char *s); /** * skips all of the characters in the given string in the fp, moving * the position to the first character that is not in *s. * \param[in] *fp file to use * \param[in] *s characters to skip * \return void */ void ldns_fskipcs(FILE *fp, const char *s); /** * skips all of the characters in the given string in the fp, moving * the position to the first character that is not in *s. * \param[in] *fp file to use * \param[in] *s characters to skip * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes) * \return void */ void ldns_fskipcs_l(FILE *fp, const char *s, int *line_nr); #ifdef __cplusplus } #endif #endif /* LDNS_PARSE_H */ Net-LDNS-0.75/include/ldns/radix.h000644 000770 000024 00000014200 12471046240 017154 0ustar00calledstaff000000 000000 /* * radix.h -- generic radix tree * * Copyright (c) 2012, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * \file * Radix tree. Implementation taken from NSD 4, adjusted for use in ldns. * */ #ifndef LDNS_RADIX_H_ #define LDNS_RADIX_H_ #include #ifdef __cplusplus extern "C" { #endif typedef uint16_t radix_strlen_t; typedef struct ldns_radix_array_t ldns_radix_array_t; typedef struct ldns_radix_node_t ldns_radix_node_t; typedef struct ldns_radix_t ldns_radix_t; /** Radix node select edge array */ struct ldns_radix_array_t { /** Additional string after the selection byte for this edge. */ uint8_t* str; /** Length of additional string for this edge. */ radix_strlen_t len; /** Node that deals with byte+str. */ ldns_radix_node_t* edge; }; /** A node in a radix tree */ struct ldns_radix_node_t { /** Key corresponding to this node. */ uint8_t* key; /** Key length corresponding to this node. */ radix_strlen_t klen; /** Data corresponding to this node. */ void* data; /** Parent node. */ ldns_radix_node_t* parent; /** Index in the the parent node select edge array. */ uint8_t parent_index; /** Length of the array. */ uint16_t len; /** Offset of the array. */ uint16_t offset; /** Capacity of the array. */ uint16_t capacity; /** Select edge array. */ ldns_radix_array_t* array; }; /** An entire radix tree */ struct ldns_radix_t { /** Root. */ ldns_radix_node_t* root; /** Number of nodes in tree. */ size_t count; }; /** * Create a new radix tree. * @return: new radix tree. * */ ldns_radix_t* ldns_radix_create(void); /** * Initialize radix tree. * @param tree: uninitialized radix tree. * */ void ldns_radix_init(ldns_radix_t* tree); /** * Free the radix tree. * @param tree: radix tree. * */ void ldns_radix_free(ldns_radix_t* tree); /** * Insert data into the tree. * @param tree: tree to insert to. * @param key: key. * @param len: length of key. * @param data: data. * @return: status. * */ ldns_status ldns_radix_insert(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len, void* data); /** * Delete data from the tree. * @param tree: tree to insert to. * @param key: key. * @param len: length of key. * @return: unlinked data or NULL if not present. * */ void* ldns_radix_delete(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len); /** * Search data in the tree. * @param tree: tree to insert to. * @param key: key. * @param len: length of key. * @return: the radix node or NULL if not found. * */ ldns_radix_node_t* ldns_radix_search(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len); /** * Search data in the tree, and if not found, find the closest smaller * element in the tree. * @param tree: tree to insert to. * @param key: key. * @param len: length of key. * @param result: the radix node with the exact or closest match. NULL if * the key is smaller than the smallest key in the tree. * @return 1 if exact match, 0 otherwise. * */ int ldns_radix_find_less_equal(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len, ldns_radix_node_t** result); /** * Get the first element in the tree. * @param tree: tree. * @return: the radix node with the first element. * */ ldns_radix_node_t* ldns_radix_first(ldns_radix_t* tree); /** * Get the last element in the tree. * @param tree: tree. * @return: the radix node with the last element. * */ ldns_radix_node_t* ldns_radix_last(ldns_radix_t* tree); /** * Next element. * @param node: node. * @return: node with next element. * */ ldns_radix_node_t* ldns_radix_next(ldns_radix_node_t* node); /** * Previous element. * @param node: node. * @return: node with previous element. * */ ldns_radix_node_t* ldns_radix_prev(ldns_radix_node_t* node); /** * Split radix tree intwo. * @param tree1: one tree. * @param num: number of elements to split off. * @param tree2: another tree. * @return: status. * */ ldns_status ldns_radix_split(ldns_radix_t* tree1, size_t num, ldns_radix_t** tree2); /** * Join two radix trees. * @param tree1: one tree. * @param tree2: another tree. * @return: status. * */ ldns_status ldns_radix_join(ldns_radix_t* tree1, ldns_radix_t* tree2); /** * Call function for all nodes in the tree, such that leaf nodes are * called before parent nodes. * @param node: start node. * @param func: function. * @param arg: user argument. * */ void ldns_radix_traverse_postorder(ldns_radix_node_t* node, void (*func)(ldns_radix_node_t*, void*), void* arg); /** * Print radix tree (for debugging purposes). * @param fd: file descriptor. * @param tree: tree. * */ void ldns_radix_printf(FILE* fd, ldns_radix_t* tree); #ifdef __cplusplus } #endif #endif /* LDNS_RADIX_H_ */ Net-LDNS-0.75/include/ldns/rbtree.h000644 000770 000024 00000016512 12471046240 017340 0ustar00calledstaff000000 000000 /* * rbtree.h -- generic red-black tree * * Copyright (c) 2001-2008, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * \file * Red black tree. Implementation taken from NSD 3.0.5, adjusted for use * in unbound (memory allocation, logging and so on). */ #ifndef LDNS_RBTREE_H_ #define LDNS_RBTREE_H_ #ifdef __cplusplus extern "C" { #endif /** * This structure must be the first member of the data structure in * the rbtree. This allows easy casting between an rbnode_t and the * user data (poor man's inheritance). * Or you can use the data pointer member to get to your data item. */ typedef struct ldns_rbnode_t ldns_rbnode_t; /** * The rbnode_t struct definition. */ struct ldns_rbnode_t { /** parent in rbtree, RBTREE_NULL for root */ ldns_rbnode_t *parent; /** left node (smaller items) */ ldns_rbnode_t *left; /** right node (larger items) */ ldns_rbnode_t *right; /** pointer to sorting key */ const void *key; /** pointer to data */ const void *data; /** colour of this node */ uint8_t color; }; /** The nullpointer, points to empty node */ #define LDNS_RBTREE_NULL &ldns_rbtree_null_node /** the global empty node */ extern ldns_rbnode_t ldns_rbtree_null_node; /** An entire red black tree */ typedef struct ldns_rbtree_t ldns_rbtree_t; /** definition for tree struct */ struct ldns_rbtree_t { /** The root of the red-black tree */ ldns_rbnode_t *root; /** The number of the nodes in the tree */ size_t count; /** * Key compare function. <0,0,>0 like strcmp. * Return 0 on two NULL ptrs. */ int (*cmp) (const void *, const void *); }; /** * Create new tree (malloced) with given key compare function. * @param cmpf: compare function (like strcmp) takes pointers to two keys. * @return: new tree, empty. */ ldns_rbtree_t *ldns_rbtree_create(int (*cmpf)(const void *, const void *)); /** * Free the complete tree (but not its keys) * @param rbtree The tree to free */ void ldns_rbtree_free(ldns_rbtree_t *rbtree); /** * Init a new tree (malloced by caller) with given key compare function. * @param rbtree: uninitialised memory for new tree, returned empty. * @param cmpf: compare function (like strcmp) takes pointers to two keys. */ void ldns_rbtree_init(ldns_rbtree_t *rbtree, int (*cmpf)(const void *, const void *)); /** * Insert data into the tree. * @param rbtree: tree to insert to. * @param data: element to insert. * @return: data ptr or NULL if key already present. */ ldns_rbnode_t *ldns_rbtree_insert(ldns_rbtree_t *rbtree, ldns_rbnode_t *data); /** * Insert data into the tree (reversed arguments, for use as callback) * \param[in] data element to insert * \param[out] rbtree tree to insert in to * \return data ptr or NULL if key is already present */ void ldns_rbtree_insert_vref(ldns_rbnode_t *data, void *rbtree); /** * Delete element from tree. * @param rbtree: tree to delete from. * @param key: key of item to delete. * @return: node that is now unlinked from the tree. User to delete it. * returns 0 if node not present */ ldns_rbnode_t *ldns_rbtree_delete(ldns_rbtree_t *rbtree, const void *key); /** * Find key in tree. Returns NULL if not found. * @param rbtree: tree to find in. * @param key: key that must match. * @return: node that fits or NULL. */ ldns_rbnode_t *ldns_rbtree_search(ldns_rbtree_t *rbtree, const void *key); /** * Find, but match does not have to be exact. * @param rbtree: tree to find in. * @param key: key to find position of. * @param result: set to the exact node if present, otherwise to element that * precedes the position of key in the tree. NULL if no smaller element. * @return: true if exact match in result. Else result points to <= element, * or NULL if key is smaller than the smallest key. */ int ldns_rbtree_find_less_equal(ldns_rbtree_t *rbtree, const void *key, ldns_rbnode_t **result); /** * Returns first (smallest) node in the tree * @param rbtree: tree * @return: smallest element or NULL if tree empty. */ ldns_rbnode_t *ldns_rbtree_first(ldns_rbtree_t *rbtree); /** * Returns last (largest) node in the tree * @param rbtree: tree * @return: largest element or NULL if tree empty. */ ldns_rbnode_t *ldns_rbtree_last(ldns_rbtree_t *rbtree); /** * Returns next larger node in the tree * @param rbtree: tree * @return: next larger element or NULL if no larger in tree. */ ldns_rbnode_t *ldns_rbtree_next(ldns_rbnode_t *rbtree); /** * Returns previous smaller node in the tree * @param rbtree: tree * @return: previous smaller element or NULL if no previous in tree. */ ldns_rbnode_t *ldns_rbtree_previous(ldns_rbnode_t *rbtree); /** * split off 'elements' number of elements from the start * of the name tree and return a new tree containing those * elements */ ldns_rbtree_t *ldns_rbtree_split(ldns_rbtree_t *tree, size_t elements); /** * add all node from the second tree to the first (removing them from the * second), and fix up nsec(3)s if present */ void ldns_rbtree_join(ldns_rbtree_t *tree1, ldns_rbtree_t *tree2); /** * Call with node=variable of struct* with rbnode_t as first element. * with type is the type of a pointer to that struct. */ #define LDNS_RBTREE_FOR(node, type, rbtree) \ for(node=(type)ldns_rbtree_first(rbtree); \ (ldns_rbnode_t*)node != LDNS_RBTREE_NULL; \ node = (type)ldns_rbtree_next((ldns_rbnode_t*)node)) /** * Call function for all elements in the redblack tree, such that * leaf elements are called before parent elements. So that all * elements can be safely free()d. * Note that your function must not remove the nodes from the tree. * Since that may trigger rebalances of the rbtree. * @param tree: the tree * @param func: function called with element and user arg. * The function must not alter the rbtree. * @param arg: user argument. */ void ldns_traverse_postorder(ldns_rbtree_t* tree, void (*func)(ldns_rbnode_t*, void*), void* arg); #ifdef __cplusplus } #endif #endif /* UTIL_RBTREE_H_ */ Net-LDNS-0.75/include/ldns/rdata.h000644 000770 000024 00000027670 12471046240 017157 0ustar00calledstaff000000 000000 /* * rdata.h * * rdata definitions * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ /** * \file * * Defines ldns_rdf and functions to manipulate those. */ #ifndef LDNS_RDATA_H #define LDNS_RDATA_H #include #include #ifdef __cplusplus extern "C" { #endif #define LDNS_MAX_RDFLEN 65535 #define LDNS_RDF_SIZE_BYTE 1 #define LDNS_RDF_SIZE_WORD 2 #define LDNS_RDF_SIZE_DOUBLEWORD 4 #define LDNS_RDF_SIZE_6BYTES 6 #define LDNS_RDF_SIZE_8BYTES 8 #define LDNS_RDF_SIZE_16BYTES 16 #define LDNS_NSEC3_VARS_OPTOUT_MASK 0x01 /** * The different types of RDATA fields. */ enum ldns_enum_rdf_type { /** none */ LDNS_RDF_TYPE_NONE, /** domain name */ LDNS_RDF_TYPE_DNAME, /** 8 bits */ LDNS_RDF_TYPE_INT8, /** 16 bits */ LDNS_RDF_TYPE_INT16, /** 32 bits */ LDNS_RDF_TYPE_INT32, /** A record */ LDNS_RDF_TYPE_A, /** AAAA record */ LDNS_RDF_TYPE_AAAA, /** txt string */ LDNS_RDF_TYPE_STR, /** apl data */ LDNS_RDF_TYPE_APL, /** b32 string */ LDNS_RDF_TYPE_B32_EXT, /** b64 string */ LDNS_RDF_TYPE_B64, /** hex string */ LDNS_RDF_TYPE_HEX, /** nsec type codes */ LDNS_RDF_TYPE_NSEC, /** a RR type */ LDNS_RDF_TYPE_TYPE, /** a class */ LDNS_RDF_TYPE_CLASS, /** certificate algorithm */ LDNS_RDF_TYPE_CERT_ALG, /** a key algorithm */ LDNS_RDF_TYPE_ALG, /** unknown types */ LDNS_RDF_TYPE_UNKNOWN, /** time (32 bits) */ LDNS_RDF_TYPE_TIME, /** period */ LDNS_RDF_TYPE_PERIOD, /** tsig time 48 bits */ LDNS_RDF_TYPE_TSIGTIME, /** Represents the Public Key Algorithm, HIT and Public Key fields for the HIP RR types. A HIP specific rdf type is used because of the unusual layout in wireformat (see RFC 5205 Section 5) */ LDNS_RDF_TYPE_HIP, /** variable length any type rdata where the length is specified by the first 2 bytes */ LDNS_RDF_TYPE_INT16_DATA, /** protocol and port bitmaps */ LDNS_RDF_TYPE_SERVICE, /** location data */ LDNS_RDF_TYPE_LOC, /** well known services */ LDNS_RDF_TYPE_WKS, /** NSAP */ LDNS_RDF_TYPE_NSAP, /** ATMA */ LDNS_RDF_TYPE_ATMA, /** IPSECKEY */ LDNS_RDF_TYPE_IPSECKEY, /** nsec3 hash salt */ LDNS_RDF_TYPE_NSEC3_SALT, /** nsec3 base32 string (with length byte on wire */ LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, /** 4 shorts represented as 4 * 16 bit hex numbers * separated by colons. For NID and L64. */ LDNS_RDF_TYPE_ILNP64, /** 6 * 8 bit hex numbers separated by dashes. For EUI48. */ LDNS_RDF_TYPE_EUI48, /** 8 * 8 bit hex numbers separated by dashes. For EUI64. */ LDNS_RDF_TYPE_EUI64, /** A non-zero sequence of US-ASCII letters and numbers in lower case. * For CAA. */ LDNS_RDF_TYPE_TAG, /** A encoding of the value field as specified * [RFC1035], Section 5.1., encoded as remaining rdata. * For CAA. */ LDNS_RDF_TYPE_LONG_STR, /** Since RFC7218 TLSA records can be given with mnemonics, * hence these rdata field types. But as with DNSKEYs, the output * is always numeric. */ LDNS_RDF_TYPE_CERTIFICATE_USAGE, LDNS_RDF_TYPE_SELECTOR, LDNS_RDF_TYPE_MATCHING_TYPE, /* Aliases */ LDNS_RDF_TYPE_BITMAP = LDNS_RDF_TYPE_NSEC }; typedef enum ldns_enum_rdf_type ldns_rdf_type; /** * algorithms used in CERT rrs */ enum ldns_enum_cert_algorithm { LDNS_CERT_PKIX = 1, LDNS_CERT_SPKI = 2, LDNS_CERT_PGP = 3, LDNS_CERT_IPKIX = 4, LDNS_CERT_ISPKI = 5, LDNS_CERT_IPGP = 6, LDNS_CERT_ACPKIX = 7, LDNS_CERT_IACPKIX = 8, LDNS_CERT_URI = 253, LDNS_CERT_OID = 254 }; typedef enum ldns_enum_cert_algorithm ldns_cert_algorithm; /** * Resource record data field. * * The data is a network ordered array of bytes, which size is specified by * the (16-bit) size field. To correctly parse it, use the type * specified in the (16-bit) type field with a value from \ref ldns_rdf_type. */ struct ldns_struct_rdf { /** The size of the data (in octets) */ size_t _size; /** The type of the data */ ldns_rdf_type _type; /** Pointer to the data (raw octets) */ void *_data; }; typedef struct ldns_struct_rdf ldns_rdf; /* prototypes */ /* write access functions */ /** * sets the size of the rdf. * \param[in] *rd the rdf to operate on * \param[in] size the new size * \return void */ void ldns_rdf_set_size(ldns_rdf *rd, size_t size); /** * sets the size of the rdf. * \param[in] *rd the rdf to operate on * \param[in] type the new type * \return void */ void ldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type); /** * sets the size of the rdf. * \param[in] *rd the rdf to operate on * \param[in] *data pointer to the new data * \return void */ void ldns_rdf_set_data(ldns_rdf *rd, void *data); /* read access */ /** * returns the size of the rdf. * \param[in] *rd the rdf to read from * \return uint16_t with the size */ size_t ldns_rdf_size(const ldns_rdf *rd); /** * returns the type of the rdf. We need to insert _get_ * here to prevent conflict the the rdf_type TYPE. * \param[in] *rd the rdf to read from * \return ldns_rdf_type with the type */ ldns_rdf_type ldns_rdf_get_type(const ldns_rdf *rd); /** * returns the data of the rdf. * \param[in] *rd the rdf to read from * * \return uint8_t* pointer to the rdf's data */ uint8_t *ldns_rdf_data(const ldns_rdf *rd); /* creator functions */ /** * allocates a new rdf structure and fills it. * This function DOES NOT copy the contents from * the buffer, unlinke ldns_rdf_new_frm_data() * \param[in] type type of the rdf * \param[in] size size of the buffer * \param[in] data pointer to the buffer to be copied * \return the new rdf structure or NULL on failure */ ldns_rdf *ldns_rdf_new(ldns_rdf_type type, size_t size, void *data); /** * allocates a new rdf structure and fills it. * This function _does_ copy the contents from * the buffer, unlinke ldns_rdf_new() * \param[in] type type of the rdf * \param[in] size size of the buffer * \param[in] data pointer to the buffer to be copied * \return the new rdf structure or NULL on failure */ ldns_rdf *ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data); /** * creates a new rdf from a string. * \param[in] type type to use * \param[in] str string to use * \return ldns_rdf* or NULL in case of an error */ ldns_rdf *ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str); /** * creates a new rdf from a file containing a string. * \param[out] r the new rdf * \param[in] type type to use * \param[in] fp the file pointer to use * \return LDNS_STATUS_OK or the error */ ldns_status ldns_rdf_new_frm_fp(ldns_rdf **r, ldns_rdf_type type, FILE *fp); /** * creates a new rdf from a file containing a string. * \param[out] r the new rdf * \param[in] type type to use * \param[in] fp the file pointer to use * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes) * \return LDNS_STATUS_OK or the error */ ldns_status ldns_rdf_new_frm_fp_l(ldns_rdf **r, ldns_rdf_type type, FILE *fp, int *line_nr); /* destroy functions */ /** * frees a rdf structure, leaving the * data pointer intact. * \param[in] rd the pointer to be freed * \return void */ void ldns_rdf_free(ldns_rdf *rd); /** * frees a rdf structure _and_ frees the * data. rdf should be created with _new_frm_data * \param[in] rd the rdf structure to be freed * \return void */ void ldns_rdf_deep_free(ldns_rdf *rd); /* conversion functions */ /** * returns the rdf containing the native uint8_t repr. * \param[in] type the ldns_rdf type to use * \param[in] value the uint8_t to use * \return ldns_rdf* with the converted value */ ldns_rdf *ldns_native2rdf_int8(ldns_rdf_type type, uint8_t value); /** * returns the rdf containing the native uint16_t representation. * \param[in] type the ldns_rdf type to use * \param[in] value the uint16_t to use * \return ldns_rdf* with the converted value */ ldns_rdf *ldns_native2rdf_int16(ldns_rdf_type type, uint16_t value); /** * returns an rdf that contains the given int32 value. * * Because multiple rdf types can contain an int32, the * type must be specified * \param[in] type the ldns_rdf type to use * \param[in] value the uint32_t to use * \return ldns_rdf* with the converted value */ ldns_rdf *ldns_native2rdf_int32(ldns_rdf_type type, uint32_t value); /** * returns an int16_data rdf that contains the data in the * given array, preceded by an int16 specifying the length. * * The memory is copied, and an LDNS_RDF_TYPE_INT16DATA is returned * \param[in] size the size of the data * \param[in] *data pointer to the actual data * * \return ldns_rd* the rdf with the data */ ldns_rdf *ldns_native2rdf_int16_data(size_t size, uint8_t *data); /** * reverses an rdf, only actually useful for AAAA and A records. * The returned rdf has the type LDNS_RDF_TYPE_DNAME! * \param[in] *rd rdf to be reversed * \return the reversed rdf (a newly created rdf) */ ldns_rdf *ldns_rdf_address_reverse(ldns_rdf *rd); /** * returns the native uint8_t representation from the rdf. * \param[in] rd the ldns_rdf to operate on * \return uint8_t the value extracted */ uint8_t ldns_rdf2native_int8(const ldns_rdf *rd); /** * returns the native uint16_t representation from the rdf. * \param[in] rd the ldns_rdf to operate on * \return uint16_t the value extracted */ uint16_t ldns_rdf2native_int16(const ldns_rdf *rd); /** * returns the native uint32_t representation from the rdf. * \param[in] rd the ldns_rdf to operate on * \return uint32_t the value extracted */ uint32_t ldns_rdf2native_int32(const ldns_rdf *rd); /** * returns the native time_t representation from the rdf. * \param[in] rd the ldns_rdf to operate on * \return time_t the value extracted (32 bits currently) */ time_t ldns_rdf2native_time_t(const ldns_rdf *rd); /** * converts a ttl value (like 5d2h) to a long. * \param[in] nptr the start of the string * \param[out] endptr points to the last char in case of error * \return the convert duration value */ uint32_t ldns_str2period(const char *nptr, const char **endptr); /** * removes \\DDD, \\[space] and other escapes from the input. * See RFC 1035, section 5.1. * \param[in] word what to check * \param[in] length the string * \return ldns_status mesg */ ldns_status ldns_octet(char *word, size_t *length); /** * clones a rdf structure. The data is copied. * \param[in] rd rdf to be copied * \return a new rdf structure */ ldns_rdf *ldns_rdf_clone(const ldns_rdf *rd); /** * compares two rdf's on their wire formats. * (To order dnames according to rfc4034, use ldns_dname_compare) * \param[in] rd1 the first one * \param[in] rd2 the second one * \return 0 if equal * \return -1 if rd1 comes before rd2 * \return +1 if rd2 comes before rd1 */ int ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2); /** * Gets the algorithm value, the HIT and Public Key data from the rdf with * type LDNS_RDF_TYPE_HIP. * \param[in] rdf the rdf with type LDNS_RDF_TYPE_HIP * \param[out] alg the algorithm * \param[out] hit_size the size of the HIT data * \param[out] hit the hit data * \param[out] pk_size the size of the Public Key data * \param[out] pk the Public Key data * \return LDNS_STATUS_OK on success, and the error otherwise */ ldns_status ldns_rdf_hip_get_alg_hit_pk(ldns_rdf *rdf, uint8_t* alg, uint8_t *hit_size, uint8_t** hit, uint16_t *pk_size, uint8_t** pk); /** * Creates a new LDNS_RDF_TYPE_HIP rdf from given data. * \param[out] rdf the newly created LDNS_RDF_TYPE_HIP rdf * \param[in] alg the algorithm * \param[in] hit_size the size of the HIT data * \param[in] hit the hit data * \param[in] pk_size the size of the Public Key data * \param[in] pk the Public Key data * \return LDNS_STATUS_OK on success, and the error otherwise */ ldns_status ldns_rdf_hip_new_frm_alg_hit_pk(ldns_rdf** rdf, uint8_t alg, uint8_t hit_size, uint8_t *hit, uint16_t pk_size, uint8_t *pk); #ifdef __cplusplus } #endif #endif /* LDNS_RDATA_H */ Net-LDNS-0.75/include/ldns/resolver.h000644 000770 000024 00000060077 12471046240 017723 0ustar00calledstaff000000 000000 /* * resolver.h * * DNS Resolver definitions * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ /** * \file * * Defines the ldns_resolver structure, a stub resolver that can send queries and parse answers. * */ #ifndef LDNS_RESOLVER_H #define LDNS_RESOLVER_H #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** Default location of the resolv.conf file */ #define LDNS_RESOLV_CONF "/etc/resolv.conf" /** Default location of the hosts file */ #define LDNS_RESOLV_HOSTS "/etc/hosts" #define LDNS_RESOLV_KEYWORD -1 #define LDNS_RESOLV_DEFDOMAIN 0 #define LDNS_RESOLV_NAMESERVER 1 #define LDNS_RESOLV_SEARCH 2 #define LDNS_RESOLV_SORTLIST 3 #define LDNS_RESOLV_OPTIONS 4 #define LDNS_RESOLV_ANCHOR 5 #define LDNS_RESOLV_KEYWORDS 6 #define LDNS_RESOLV_INETANY 0 #define LDNS_RESOLV_INET 1 #define LDNS_RESOLV_INET6 2 #define LDNS_RESOLV_RTT_INF 0 /* infinity */ #define LDNS_RESOLV_RTT_MIN 1 /* reachable */ /** * DNS stub resolver structure */ struct ldns_struct_resolver { /** Port to send queries to */ uint16_t _port; /** Array of nameservers to query (IP addresses or dnames) */ ldns_rdf **_nameservers; /** Number of nameservers in \c _nameservers */ size_t _nameserver_count; /* how many do we have */ /** Round trip time; 0 -> infinity. Unit: ms? */ size_t *_rtt; /** Whether or not to be recursive */ bool _recursive; /** Print debug information */ bool _debug; /** Default domain to add to non fully qualified domain names */ ldns_rdf *_domain; /** Searchlist array, add the names in this array if a query cannot be found */ ldns_rdf **_searchlist; /** Number of entries in the searchlist array */ size_t _searchlist_count; /** Number of times to retry before giving up */ uint8_t _retry; /** Time to wait before retrying */ uint8_t _retrans; /** Use new fallback mechanism (try EDNS, then do TCP) */ bool _fallback; /** Whether to do DNSSEC */ bool _dnssec; /** Whether to set the CD bit on DNSSEC requests */ bool _dnssec_cd; /** Optional trust anchors for complete DNSSEC validation */ ldns_rr_list * _dnssec_anchors; /** Whether to use tcp or udp (tcp if the value is true)*/ bool _usevc; /** Whether to ignore the tc bit */ bool _igntc; /** Whether to use ip6: 0->does not matter, 1 is IPv4, 2 is IPv6 */ uint8_t _ip6; /** If true append the default domain */ bool _defnames; /** If true apply the search list */ bool _dnsrch; /** Timeout for socket connections */ struct timeval _timeout; /** Only try the first nameserver, and return with an error directly if it fails */ bool _fail; /** Randomly choose a nameserver */ bool _random; /** Keep some things to make AXFR possible */ int _socket; /** Count the number of LDNS_RR_TYPE_SOA RRs we have seen so far * (the second one signifies the end of the AXFR) */ int _axfr_soa_count; /* when axfring we get complete packets from the server but we want to give the caller 1 rr at a time, so keep the current pkt */ /** Packet currently handled when doing part of an AXFR */ ldns_pkt *_cur_axfr_pkt; /** Counter for within the AXFR packets */ uint16_t _axfr_i; /* EDNS0 available buffer size */ uint16_t _edns_udp_size; /* serial for IXFR */ uint32_t _serial; /* Optional tsig key for signing queries, outgoing messages are signed if and only if both are set */ /** Name of the key to use with TSIG, if _tsig_keyname and _tsig_keydata both contain values, outgoing messages are automatically signed with TSIG. */ char *_tsig_keyname; /** Secret key data to use with TSIG, if _tsig_keyname and _tsig_keydata both contain values, outgoing messages are automatically signed with TSIG. */ char *_tsig_keydata; /** TSIG signing algorithm */ char *_tsig_algorithm; /** Source address to query from */ ldns_rdf *_source; }; typedef struct ldns_struct_resolver ldns_resolver; /* prototypes */ /* read access functions */ /** * Get the port the resolver should use * \param[in] r the resolver * \return the port number */ uint16_t ldns_resolver_port(const ldns_resolver *r); /** * Get the source address the resolver should use * \param[in] r the resolver * \return the source rdf */ ldns_rdf *ldns_resolver_source(const ldns_resolver *r); /** * Is the resolver set to recurse * \param[in] r the resolver * \return true if so, otherwise false */ bool ldns_resolver_recursive(const ldns_resolver *r); /** * Get the debug status of the resolver * \param[in] r the resolver * \return true if so, otherwise false */ bool ldns_resolver_debug(const ldns_resolver *r); /** * Get the number of retries * \param[in] r the resolver * \return the number of retries */ uint8_t ldns_resolver_retry(const ldns_resolver *r); /** * Get the retransmit interval * \param[in] r the resolver * \return the retransmit interval */ uint8_t ldns_resolver_retrans(const ldns_resolver *r); /** * Get the truncation fallback status * \param[in] r the resolver * \return whether the truncation fallback mechanism is used */ bool ldns_resolver_fallback(const ldns_resolver *r); /** * Does the resolver use ip6 or ip4 * \param[in] r the resolver * \return 0: both, 1: ip4, 2:ip6 */ uint8_t ldns_resolver_ip6(const ldns_resolver *r); /** * Get the resolver's udp size * \param[in] r the resolver * \return the udp mesg size */ uint16_t ldns_resolver_edns_udp_size(const ldns_resolver *r); /** * Does the resolver use tcp or udp * \param[in] r the resolver * \return true: tcp, false: udp */ bool ldns_resolver_usevc(const ldns_resolver *r); /** * Does the resolver only try the first nameserver * \param[in] r the resolver * \return true: yes, fail, false: no, try the others */ bool ldns_resolver_fail(const ldns_resolver *r); /** * Does the resolver apply default domain name * \param[in] r the resolver * \return true: yes, false: no */ bool ldns_resolver_defnames(const ldns_resolver *r); /** * Does the resolver apply search list * \param[in] r the resolver * \return true: yes, false: no */ bool ldns_resolver_dnsrch(const ldns_resolver *r); /** * Does the resolver do DNSSEC * \param[in] r the resolver * \return true: yes, false: no */ bool ldns_resolver_dnssec(const ldns_resolver *r); /** * Does the resolver set the CD bit * \param[in] r the resolver * \return true: yes, false: no */ bool ldns_resolver_dnssec_cd(const ldns_resolver *r); /** * Get the resolver's DNSSEC anchors * \param[in] r the resolver * \return an rr_list containg trusted DNSSEC anchors */ ldns_rr_list * ldns_resolver_dnssec_anchors(const ldns_resolver *r); /** * Does the resolver ignore the TC bit (truncated) * \param[in] r the resolver * \return true: yes, false: no */ bool ldns_resolver_igntc(const ldns_resolver *r); /** * Does the resolver randomize the nameserver before usage * \param[in] r the resolver * \return true: yes, false: no */ bool ldns_resolver_random(const ldns_resolver *r); /** * How many nameserver are configured in the resolver * \param[in] r the resolver * \return number of nameservers */ size_t ldns_resolver_nameserver_count(const ldns_resolver *r); /** * What is the default dname to add to relative queries * \param[in] r the resolver * \return the dname which is added */ ldns_rdf *ldns_resolver_domain(const ldns_resolver *r); /** * What is the timeout on socket connections * \param[in] r the resolver * \return the timeout as struct timeval */ struct timeval ldns_resolver_timeout(const ldns_resolver *r); /** * What is the searchlist as used by the resolver * \param[in] r the resolver * \return a ldns_rdf pointer to a list of the addresses */ ldns_rdf** ldns_resolver_searchlist(const ldns_resolver *r); /** * Return the configured nameserver ip address * \param[in] r the resolver * \return a ldns_rdf pointer to a list of the addresses */ ldns_rdf** ldns_resolver_nameservers(const ldns_resolver *r); /** * Return the used round trip times for the nameservers * \param[in] r the resolver * \return a size_t* pointer to the list. * yet) */ size_t * ldns_resolver_rtt(const ldns_resolver *r); /** * Return the used round trip time for a specific nameserver * \param[in] r the resolver * \param[in] pos the index to the nameserver * \return the rrt, 0: infinite, >0: undefined (as of * yet) */ size_t ldns_resolver_nameserver_rtt(const ldns_resolver *r, size_t pos); /** * Return the tsig keyname as used by the nameserver * \param[in] r the resolver * \return the name used. */ char *ldns_resolver_tsig_keyname(const ldns_resolver *r); /** * Return the tsig algorithm as used by the nameserver * \param[in] r the resolver * \return the algorithm used. */ char *ldns_resolver_tsig_algorithm(const ldns_resolver *r); /** * Return the tsig keydata as used by the nameserver * \param[in] r the resolver * \return the keydata used. */ char *ldns_resolver_tsig_keydata(const ldns_resolver *r); /** * pop the last nameserver from the resolver. * \param[in] r the resolver * \return the popped address or NULL if empty */ ldns_rdf* ldns_resolver_pop_nameserver(ldns_resolver *r); /** * Return the resolver's searchlist count * \param[in] r the resolver * \return the searchlist count */ size_t ldns_resolver_searchlist_count(const ldns_resolver *r); /* write access function */ /** * Set the port the resolver should use * \param[in] r the resolver * \param[in] p the port number */ void ldns_resolver_set_port(ldns_resolver *r, uint16_t p); /** * Set the source rdf (address) the resolver should use * \param[in] r the resolver * \param[in] s the source address */ void ldns_resolver_set_source(ldns_resolver *r, ldns_rdf *s); /** * Set the resolver recursion * \param[in] r the resolver * \param[in] b true: set to recurse, false: unset */ void ldns_resolver_set_recursive(ldns_resolver *r, bool b); /** * Set the resolver debugging * \param[in] r the resolver * \param[in] b true: debug on: false debug off */ void ldns_resolver_set_debug(ldns_resolver *r, bool b); /** * Incremental the resolver's nameserver count. * \param[in] r the resolver */ void ldns_resolver_incr_nameserver_count(ldns_resolver *r); /** * Decrement the resolver's nameserver count. * \param[in] r the resolver */ void ldns_resolver_dec_nameserver_count(ldns_resolver *r); /** * Set the resolver's nameserver count directly. * \param[in] r the resolver * \param[in] c the nameserver count */ void ldns_resolver_set_nameserver_count(ldns_resolver *r, size_t c); /** * Set the resolver's nameserver count directly by using an rdf list * \param[in] r the resolver * \param[in] rd the resolver addresses */ void ldns_resolver_set_nameservers(ldns_resolver *r, ldns_rdf **rd); /** * Set the resolver's default domain. This gets appended when no * absolute name is given * \param[in] r the resolver * \param[in] rd the name to append */ void ldns_resolver_set_domain(ldns_resolver *r, ldns_rdf *rd); /** * Set the resolver's socket time out when talking to remote hosts * \param[in] r the resolver * \param[in] timeout the timeout to use */ void ldns_resolver_set_timeout(ldns_resolver *r, struct timeval timeout); /** * Push a new rd to the resolver's searchlist * \param[in] r the resolver * \param[in] rd to push */ void ldns_resolver_push_searchlist(ldns_resolver *r, ldns_rdf *rd); /** * Whether the resolver uses the name set with _set_domain * \param[in] r the resolver * \param[in] b true: use the defaults, false: don't use them */ void ldns_resolver_set_defnames(ldns_resolver *r, bool b); /** * Whether the resolver uses a virtual circuit (TCP) * \param[in] r the resolver * \param[in] b true: use TCP, false: don't use TCP */ void ldns_resolver_set_usevc(ldns_resolver *r, bool b); /** * Whether the resolver uses the searchlist * \param[in] r the resolver * \param[in] b true: use the list, false: don't use the list */ void ldns_resolver_set_dnsrch(ldns_resolver *r, bool b); /** * Whether the resolver uses DNSSEC * \param[in] r the resolver * \param[in] b true: use DNSSEC, false: don't use DNSSEC */ void ldns_resolver_set_dnssec(ldns_resolver *r, bool b); /** * Whether the resolver uses the checking disable bit * \param[in] r the resolver * \param[in] b true: enable , false: don't use TCP */ void ldns_resolver_set_dnssec_cd(ldns_resolver *r, bool b); /** * Set the resolver's DNSSEC anchor list directly. RRs should be of type DS or DNSKEY. * \param[in] r the resolver * \param[in] l the list of RRs to use as trust anchors */ void ldns_resolver_set_dnssec_anchors(ldns_resolver *r, ldns_rr_list * l); /** * Push a new trust anchor to the resolver. It must be a DS or DNSKEY rr * \param[in] r the resolver. * \param[in] rr the RR to add as a trust anchor. * \return a status */ ldns_status ldns_resolver_push_dnssec_anchor(ldns_resolver *r, ldns_rr *rr); /** * Set the resolver retrans timeout (in seconds) * \param[in] r the resolver * \param[in] re the retransmission interval in seconds */ void ldns_resolver_set_retrans(ldns_resolver *r, uint8_t re); /** * Set whether the resolvers truncation fallback mechanism is used * when ldns_resolver_query() is called. * \param[in] r the resolver * \param[in] fallback whether to use the fallback mechanism */ void ldns_resolver_set_fallback(ldns_resolver *r, bool fallback); /** * Set the number of times a resolver should retry a nameserver before the * next one is tried. * \param[in] r the resolver * \param[in] re the number of retries */ void ldns_resolver_set_retry(ldns_resolver *r, uint8_t re); /** * Whether the resolver uses ip6 * \param[in] r the resolver * \param[in] i 0: no pref, 1: ip4, 2: ip6 */ void ldns_resolver_set_ip6(ldns_resolver *r, uint8_t i); /** * Whether or not to fail after one failed query * \param[in] r the resolver * \param[in] b true: yes fail, false: continue with next nameserver */ void ldns_resolver_set_fail(ldns_resolver *r, bool b); /** * Whether or not to ignore the TC bit * \param[in] r the resolver * \param[in] b true: yes ignore, false: don't ignore */ void ldns_resolver_set_igntc(ldns_resolver *r, bool b); /** * Set maximum udp size * \param[in] r the resolver * \param[in] s the udp max size */ void ldns_resolver_set_edns_udp_size(ldns_resolver *r, uint16_t s); /** * Set the tsig key name * \param[in] r the resolver * \param[in] tsig_keyname the tsig key name */ void ldns_resolver_set_tsig_keyname(ldns_resolver *r, char *tsig_keyname); /** * Set the tsig algorithm * \param[in] r the resolver * \param[in] tsig_algorithm the tsig algorithm */ void ldns_resolver_set_tsig_algorithm(ldns_resolver *r, char *tsig_algorithm); /** * Set the tsig key data * \param[in] r the resolver * \param[in] tsig_keydata the key data */ void ldns_resolver_set_tsig_keydata(ldns_resolver *r, char *tsig_keydata); /** * Set round trip time for all nameservers. Note this currently * differentiates between: unreachable and reachable. * \param[in] r the resolver * \param[in] rtt a list with the times */ void ldns_resolver_set_rtt(ldns_resolver *r, size_t *rtt); /** * Set round trip time for a specific nameserver. Note this * currently differentiates between: unreachable and reachable. * \param[in] r the resolver * \param[in] pos the nameserver position * \param[in] value the rtt */ void ldns_resolver_set_nameserver_rtt(ldns_resolver *r, size_t pos, size_t value); /** * Should the nameserver list be randomized before each use * \param[in] r the resolver * \param[in] b: true: randomize, false: don't */ void ldns_resolver_set_random(ldns_resolver *r, bool b); /** * Push a new nameserver to the resolver. It must be an IP * address v4 or v6. * \param[in] r the resolver * \param[in] n the ip address * \return ldns_status a status */ ldns_status ldns_resolver_push_nameserver(ldns_resolver *r, ldns_rdf *n); /** * Push a new nameserver to the resolver. It must be an * A or AAAA RR record type * \param[in] r the resolver * \param[in] rr the resource record * \return ldns_status a status */ ldns_status ldns_resolver_push_nameserver_rr(ldns_resolver *r, ldns_rr *rr); /** * Push a new nameserver rr_list to the resolver. * \param[in] r the resolver * \param[in] rrlist the rr_list to push * \return ldns_status a status */ ldns_status ldns_resolver_push_nameserver_rr_list(ldns_resolver *r, ldns_rr_list *rrlist); /** * Send the query for using the resolver and take the search list into account * The search algorithm is as follows: * If the name is absolute, try it as-is, otherwise apply the search list * \param[in] *r operate using this resolver * \param[in] *rdf query for this name * \param[in] t query for this type (may be 0, defaults to A) * \param[in] c query for this class (may be 0, default to IN) * \param[in] flags the query flags * * \return ldns_pkt* a packet with the reply from the nameserver */ ldns_pkt* ldns_resolver_search(const ldns_resolver *r, const ldns_rdf *rdf, ldns_rr_type t, ldns_rr_class c, uint16_t flags); /** * Send the query for using the resolver and take the search list into account * The search algorithm is as follows: * If the name is absolute, try it as-is, otherwise apply the search list * \param[out] pkt a packet with the reply from the nameserver * \param[in] *r operate using this resolver * \param[in] *rdf query for this name * \param[in] t query for this type (may be 0, defaults to A) * \param[in] c query for this class (may be 0, default to IN) * \param[in] flags the query flags * * \return ldns_status LDNS_STATUS_OK on success */ ldns_status ldns_resolver_search_status(ldns_pkt** pkt, ldns_resolver *r, const ldns_rdf *rdf, ldns_rr_type t, ldns_rr_class c, uint16_t flags); /** * Form a query packet from a resolver and name/type/class combo * \param[out] **q a pointer to a ldns_pkt pointer (initialized by this function) * \param[in] *r operate using this resolver * \param[in] *name query for this name * \param[in] t query for this type (may be 0, defaults to A) * \param[in] c query for this class (may be 0, default to IN) * \param[in] f the query flags * * \return ldns_pkt* a packet with the reply from the nameserver */ ldns_status ldns_resolver_prepare_query_pkt(ldns_pkt **q, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t f); /** * Send the query for name as-is * \param[out] **answer a pointer to a ldns_pkt pointer (initialized by this function) * \param[in] *r operate using this resolver * \param[in] *name query for this name * \param[in] t query for this type (may be 0, defaults to A) * \param[in] c query for this class (may be 0, default to IN) * \param[in] flags the query flags * * \return ldns_pkt* a packet with the reply from the nameserver */ ldns_status ldns_resolver_send(ldns_pkt **answer, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags); /** * Send the given packet to a nameserver * \param[out] **answer a pointer to a ldns_pkt pointer (initialized by this function) * \param[in] *r operate using this resolver * \param[in] *query_pkt query */ ldns_status ldns_resolver_send_pkt(ldns_pkt **answer, ldns_resolver *r, ldns_pkt *query_pkt); /** * Send a query to a nameserver * \param[out] pkt a packet with the reply from the nameserver * \param[in] *r operate using this resolver * \param[in] *name query for this name * \param[in] *t query for this type (may be 0, defaults to A) * \param[in] *c query for this class (may be 0, default to IN) * \param[in] flags the query flags * * \return ldns_status LDNS_STATUS_OK on success * if _defnames is true the default domain will be added */ ldns_status ldns_resolver_query_status(ldns_pkt** pkt, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags); /** * Send a query to a nameserver * \param[in] *r operate using this resolver * (despite the const in the declaration, * the struct is altered as a side-effect) * \param[in] *name query for this name * \param[in] *t query for this type (may be 0, defaults to A) * \param[in] *c query for this class (may be 0, default to IN) * \param[in] flags the query flags * * \return ldns_pkt* a packet with the reply from the nameserver * if _defnames is true the default domain will be added */ ldns_pkt* ldns_resolver_query(const ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags); /** * Create a new resolver structure * \return ldns_resolver* pointer to new structure */ ldns_resolver* ldns_resolver_new(void); /** * Clone a resolver * \param[in] r the resolver to clone * \return ldns_resolver* pointer to new structure */ ldns_resolver* ldns_resolver_clone(ldns_resolver *r); /** * Create a resolver structure from a file like /etc/resolv.conf * \param[out] r the new resolver * \param[in] fp file pointer to create new resolver from * if NULL use /etc/resolv.conf * \return LDNS_STATUS_OK or the error */ ldns_status ldns_resolver_new_frm_fp(ldns_resolver **r, FILE *fp); /** * Create a resolver structure from a file like /etc/resolv.conf * \param[out] r the new resolver * \param[in] fp file pointer to create new resolver from * if NULL use /etc/resolv.conf * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes) * \return LDNS_STATUS_OK or the error */ ldns_status ldns_resolver_new_frm_fp_l(ldns_resolver **r, FILE *fp, int *line_nr); /** * Configure a resolver by means of a resolv.conf file * The file may be NULL in which case there will be * looked the RESOLV_CONF (defaults to /etc/resolv.conf * \param[out] r the new resolver * \param[in] filename the filename to use * \return LDNS_STATUS_OK or the error */ ldns_status ldns_resolver_new_frm_file(ldns_resolver **r, const char *filename); /** * Frees the allocated space for this resolver. Only frees the resolver pionter! You should probably be using _deep_free. * \param res resolver to free */ void ldns_resolver_free(ldns_resolver *res); /** * Frees the allocated space for this resolver and all it's data * \param res resolver to free */ void ldns_resolver_deep_free(ldns_resolver *res); /** * Get the next stream of RRs in a AXFR * \param[in] resolver the resolver to use. First ldns_axfr_start() must be * called * \return ldns_rr the next RR from the AXFR stream * After you get this returned RR (not NULL: on error), then check if * ldns_axfr_complete() is true to see if the zone transfer has completed. */ ldns_rr* ldns_axfr_next(ldns_resolver *resolver); /** * Abort a transfer that is in progress * \param[in] resolver the resolver that is used */ void ldns_axfr_abort(ldns_resolver *resolver); /** * Returns true if the axfr transfer has completed (i.e. 2 SOA RRs and no errors were encountered * \param[in] resolver the resolver that is used * \return bool true if axfr transfer was completed without error */ bool ldns_axfr_complete(const ldns_resolver *resolver); /** * Returns a pointer to the last ldns_pkt that was sent by the server in the AXFR transfer * uasable for instance to get the error code on failure * \param[in] res the resolver that was used in the axfr transfer * \return ldns_pkt the last packet sent */ ldns_pkt *ldns_axfr_last_pkt(const ldns_resolver *res); /** * Get the serial for requesting IXFR. * \param[in] r the resolver * \param[in] serial serial */ void ldns_resolver_set_ixfr_serial(ldns_resolver *r, uint32_t serial); /** * Get the serial for requesting IXFR. * \param[in] res the resolver * \return uint32_t serial */ uint32_t ldns_resolver_get_ixfr_serial(const ldns_resolver *res); /** * Randomize the nameserver list in the resolver * \param[in] r the resolver */ void ldns_resolver_nameservers_randomize(ldns_resolver *r); /** * Returns true if at least one of the provided keys is a trust anchor * \param[in] r the current resolver * \param[in] keys the keyset to check * \param[out] trusted_keys the subset of trusted keys in the 'keys' rrset * \return true if at least one of the provided keys is a configured trust anchor */ bool ldns_resolver_trusted_key(const ldns_resolver *r, ldns_rr_list * keys, ldns_rr_list * trusted_keys); #ifdef __cplusplus } #endif #endif /* LDNS_RESOLVER_H */ Net-LDNS-0.75/include/ldns/rr.h000644 000770 000024 00000065625 12471046240 016511 0ustar00calledstaff000000 000000 /* * rr.h - resource record definitions * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ /** * \file * * Contains the definition of ldns_rr and functions to manipulate those. */ #ifndef LDNS_RR_H #define LDNS_RR_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** Maximum length of a dname label */ #define LDNS_MAX_LABELLEN 63 /** Maximum length of a complete dname */ #define LDNS_MAX_DOMAINLEN 255 /** Maximum number of pointers in 1 dname */ #define LDNS_MAX_POINTERS 65535 /** The bytes TTL, CLASS and length use up in an rr */ #define LDNS_RR_OVERHEAD 10 /* The first fields are contiguous and can be referenced instantly */ #define LDNS_RDATA_FIELD_DESCRIPTORS_COMMON 258 /** * The different RR classes. */ enum ldns_enum_rr_class { /** the Internet */ LDNS_RR_CLASS_IN = 1, /** Chaos class */ LDNS_RR_CLASS_CH = 3, /** Hesiod (Dyer 87) */ LDNS_RR_CLASS_HS = 4, /** None class, dynamic update */ LDNS_RR_CLASS_NONE = 254, /** Any class */ LDNS_RR_CLASS_ANY = 255, LDNS_RR_CLASS_FIRST = 0, LDNS_RR_CLASS_LAST = 65535, LDNS_RR_CLASS_COUNT = LDNS_RR_CLASS_LAST - LDNS_RR_CLASS_FIRST + 1 }; typedef enum ldns_enum_rr_class ldns_rr_class; /** * Used to specify whether compression is allowed. */ enum ldns_enum_rr_compress { /** compression is allowed */ LDNS_RR_COMPRESS, LDNS_RR_NO_COMPRESS }; typedef enum ldns_enum_rr_compress ldns_rr_compress; /** * The different RR types. */ enum ldns_enum_rr_type { /** a host address */ LDNS_RR_TYPE_A = 1, /** an authoritative name server */ LDNS_RR_TYPE_NS = 2, /** a mail destination (Obsolete - use MX) */ LDNS_RR_TYPE_MD = 3, /** a mail forwarder (Obsolete - use MX) */ LDNS_RR_TYPE_MF = 4, /** the canonical name for an alias */ LDNS_RR_TYPE_CNAME = 5, /** marks the start of a zone of authority */ LDNS_RR_TYPE_SOA = 6, /** a mailbox domain name (EXPERIMENTAL) */ LDNS_RR_TYPE_MB = 7, /** a mail group member (EXPERIMENTAL) */ LDNS_RR_TYPE_MG = 8, /** a mail rename domain name (EXPERIMENTAL) */ LDNS_RR_TYPE_MR = 9, /** a null RR (EXPERIMENTAL) */ LDNS_RR_TYPE_NULL = 10, /** a well known service description */ LDNS_RR_TYPE_WKS = 11, /** a domain name pointer */ LDNS_RR_TYPE_PTR = 12, /** host information */ LDNS_RR_TYPE_HINFO = 13, /** mailbox or mail list information */ LDNS_RR_TYPE_MINFO = 14, /** mail exchange */ LDNS_RR_TYPE_MX = 15, /** text strings */ LDNS_RR_TYPE_TXT = 16, /** RFC1183 */ LDNS_RR_TYPE_RP = 17, /** RFC1183 */ LDNS_RR_TYPE_AFSDB = 18, /** RFC1183 */ LDNS_RR_TYPE_X25 = 19, /** RFC1183 */ LDNS_RR_TYPE_ISDN = 20, /** RFC1183 */ LDNS_RR_TYPE_RT = 21, /** RFC1706 */ LDNS_RR_TYPE_NSAP = 22, /** RFC1348 */ LDNS_RR_TYPE_NSAP_PTR = 23, /** 2535typecode */ LDNS_RR_TYPE_SIG = 24, /** 2535typecode */ LDNS_RR_TYPE_KEY = 25, /** RFC2163 */ LDNS_RR_TYPE_PX = 26, /** RFC1712 */ LDNS_RR_TYPE_GPOS = 27, /** ipv6 address */ LDNS_RR_TYPE_AAAA = 28, /** LOC record RFC1876 */ LDNS_RR_TYPE_LOC = 29, /** 2535typecode */ LDNS_RR_TYPE_NXT = 30, /** draft-ietf-nimrod-dns-01.txt */ LDNS_RR_TYPE_EID = 31, /** draft-ietf-nimrod-dns-01.txt */ LDNS_RR_TYPE_NIMLOC = 32, /** SRV record RFC2782 */ LDNS_RR_TYPE_SRV = 33, /** http://www.jhsoft.com/rfc/af-saa-0069.000.rtf */ LDNS_RR_TYPE_ATMA = 34, /** RFC2915 */ LDNS_RR_TYPE_NAPTR = 35, /** RFC2230 */ LDNS_RR_TYPE_KX = 36, /** RFC2538 */ LDNS_RR_TYPE_CERT = 37, /** RFC2874 */ LDNS_RR_TYPE_A6 = 38, /** RFC2672 */ LDNS_RR_TYPE_DNAME = 39, /** dnsind-kitchen-sink-02.txt */ LDNS_RR_TYPE_SINK = 40, /** Pseudo OPT record... */ LDNS_RR_TYPE_OPT = 41, /** RFC3123 */ LDNS_RR_TYPE_APL = 42, /** RFC4034, RFC3658 */ LDNS_RR_TYPE_DS = 43, /** SSH Key Fingerprint */ LDNS_RR_TYPE_SSHFP = 44, /* RFC 4255 */ /** IPsec Key */ LDNS_RR_TYPE_IPSECKEY = 45, /* RFC 4025 */ /** DNSSEC */ LDNS_RR_TYPE_RRSIG = 46, /* RFC 4034 */ LDNS_RR_TYPE_NSEC = 47, /* RFC 4034 */ LDNS_RR_TYPE_DNSKEY = 48, /* RFC 4034 */ LDNS_RR_TYPE_DHCID = 49, /* RFC 4701 */ /* NSEC3 */ LDNS_RR_TYPE_NSEC3 = 50, /* RFC 5155 */ LDNS_RR_TYPE_NSEC3PARAM = 51, /* RFC 5155 */ LDNS_RR_TYPE_NSEC3PARAMS = 51, LDNS_RR_TYPE_TLSA = 52, /* RFC 6698 */ LDNS_RR_TYPE_HIP = 55, /* RFC 5205 */ /** draft-reid-dnsext-zs */ LDNS_RR_TYPE_NINFO = 56, /** draft-reid-dnsext-rkey */ LDNS_RR_TYPE_RKEY = 57, /** draft-ietf-dnsop-trust-history */ LDNS_RR_TYPE_TALINK = 58, LDNS_RR_TYPE_CDS = 59, /* RFC 7344 */ LDNS_RR_TYPE_CDNSKEY = 60, /* RFC 7344 */ /** draft-ietf-dane-openpgpkey */ LDNS_RR_TYPE_OPENPGPKEY = 61, LDNS_RR_TYPE_SPF = 99, /* RFC 4408 */ LDNS_RR_TYPE_UINFO = 100, LDNS_RR_TYPE_UID = 101, LDNS_RR_TYPE_GID = 102, LDNS_RR_TYPE_UNSPEC = 103, LDNS_RR_TYPE_NID = 104, /* RFC 6742 */ LDNS_RR_TYPE_L32 = 105, /* RFC 6742 */ LDNS_RR_TYPE_L64 = 106, /* RFC 6742 */ LDNS_RR_TYPE_LP = 107, /* RFC 6742 */ LDNS_RR_TYPE_EUI48 = 108, /* RFC 7043 */ LDNS_RR_TYPE_EUI64 = 109, /* RFC 7043 */ LDNS_RR_TYPE_TKEY = 249, /* RFC 2930 */ LDNS_RR_TYPE_TSIG = 250, LDNS_RR_TYPE_IXFR = 251, LDNS_RR_TYPE_AXFR = 252, /** A request for mailbox-related records (MB, MG or MR) */ LDNS_RR_TYPE_MAILB = 253, /** A request for mail agent RRs (Obsolete - see MX) */ LDNS_RR_TYPE_MAILA = 254, /** any type (wildcard) */ LDNS_RR_TYPE_ANY = 255, /** draft-faltstrom-uri-06 */ LDNS_RR_TYPE_URI = 256, LDNS_RR_TYPE_CAA = 257, /* RFC 6844 */ /** DNSSEC Trust Authorities */ LDNS_RR_TYPE_TA = 32768, /* RFC 4431, 5074, DNSSEC Lookaside Validation */ LDNS_RR_TYPE_DLV = 32769, /* type codes from nsec3 experimental phase LDNS_RR_TYPE_NSEC3 = 65324, LDNS_RR_TYPE_NSEC3PARAMS = 65325, */ LDNS_RR_TYPE_FIRST = 0, LDNS_RR_TYPE_LAST = 65535, LDNS_RR_TYPE_COUNT = LDNS_RR_TYPE_LAST - LDNS_RR_TYPE_FIRST + 1 }; typedef enum ldns_enum_rr_type ldns_rr_type; /** * Resource Record * * This is the basic DNS element that contains actual data * * From RFC1035: *
3.2.1. Format

All RRs have the same top level format shown below:

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                                               |
    /                                               /
    /                      NAME                     /
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      TYPE                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     CLASS                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      TTL                      |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                   RDLENGTH                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
    /                     RDATA                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

where:

NAME            an owner name, i.e., the name of the node to which this
                resource record pertains.

TYPE            two octets containing one of the RR TYPE codes.

CLASS           two octets containing one of the RR CLASS codes.

TTL             a 32 bit signed integer that specifies the time interval
                that the resource record may be cached before the source
                of the information should again be consulted.  Zero
                values are interpreted to mean that the RR can only be
                used for the transaction in progress, and should not be
                cached.  For example, SOA records are always distributed
                with a zero TTL to prohibit caching.  Zero values can
                also be used for extremely volatile data.

RDLENGTH        an unsigned 16 bit integer that specifies the length in
                octets of the RDATA field.

RDATA           a variable length string of octets that describes the
                resource.  The format of this information varies
                according to the TYPE and CLASS of the resource record.
 * 
* * The actual amount and type of rdata fields depend on the RR type of the * RR, and can be found by using \ref ldns_rr_descriptor functions. */ struct ldns_struct_rr { /** Owner name, uncompressed */ ldns_rdf *_owner; /** Time to live */ uint32_t _ttl; /** Number of data fields */ size_t _rd_count; /** the type of the RR. A, MX etc. */ ldns_rr_type _rr_type; /** Class of the resource record. */ ldns_rr_class _rr_class; /* everything in the rdata is in network order */ /** The array of rdata's */ ldns_rdf **_rdata_fields; /** question rr [it would be nicer if thous is after _rd_count] ABI change: Fix this in next major release */ bool _rr_question; }; typedef struct ldns_struct_rr ldns_rr; /** * List or Set of Resource Records * * Contains a list of rr's
* No official RFC-like checks are made */ struct ldns_struct_rr_list { size_t _rr_count; size_t _rr_capacity; ldns_rr **_rrs; }; typedef struct ldns_struct_rr_list ldns_rr_list; /** * Contains all information about resource record types. * * This structure contains, for all rr types, the rdata fields that are defined. */ struct ldns_struct_rr_descriptor { /** Type of the RR that is described here */ ldns_rr_type _type; /** Textual name of the RR type. */ const char *_name; /** Minimum number of rdata fields in the RRs of this type. */ uint8_t _minimum; /** Maximum number of rdata fields in the RRs of this type. */ uint8_t _maximum; /** Wireformat specification for the rr, i.e. the types of rdata fields in their respective order. */ const ldns_rdf_type *_wireformat; /** Special rdf types */ ldns_rdf_type _variable; /** Specifies whether compression can be used for dnames in this RR type. */ ldns_rr_compress _compress; /** The number of DNAMEs in the _wireformat string, for parsing. */ uint8_t _dname_count; }; typedef struct ldns_struct_rr_descriptor ldns_rr_descriptor; /** * Create a rr type bitmap rdf providing enough space to set all * known (to ldns) rr types. * \param[out] rdf the constructed rdf * \return LDNS_STATUS_OK if all went well. */ ldns_status ldns_rdf_bitmap_known_rr_types_space(ldns_rdf** rdf); /** * Create a rr type bitmap rdf with at least all known (to ldns) rr types set. * \param[out] rdf the constructed rdf * \return LDNS_STATUS_OK if all went well. */ ldns_status ldns_rdf_bitmap_known_rr_types(ldns_rdf** rdf); /** * creates a new rr structure. * \return ldns_rr * */ ldns_rr* ldns_rr_new(void); /** * creates a new rr structure, based on the given type. * alloc enough space to hold all the rdf's */ ldns_rr* ldns_rr_new_frm_type(ldns_rr_type t); /** * frees an RR structure * \param[in] *rr the RR to be freed * \return void */ void ldns_rr_free(ldns_rr *rr); /** * creates an rr from a string. * The string should be a fully filled-in rr, like * ownername <space> TTL <space> CLASS <space> * TYPE <space> RDATA. * \param[out] n the rr to return * \param[in] str the string to convert * \param[in] default_ttl default ttl value for the rr. * If 0 DEF_TTL will be used * \param[in] origin when the owner is relative add this. * The caller must ldns_rdf_deep_free it. * \param[out] prev the previous ownername. if this value is not NULL, * the function overwrites this with the ownername found in this * string. The caller must then ldns_rdf_deep_free it. * \return a status msg describing an error or LDNS_STATUS_OK */ ldns_status ldns_rr_new_frm_str(ldns_rr **n, const char *str, uint32_t default_ttl, ldns_rdf *origin, ldns_rdf **prev); /** * creates an rr for the question section from a string, i.e. * without RDATA fields * Origin and previous RR functionality are the same as in * ldns_rr_new_frm_str() * \param[out] n the rr to return * \param[in] str the string to convert * \param[in] origin when the owner is relative add this. * The caller must ldns_rdf_deep_free it. * \param prev the previous ownername. the function overwrite this with * the current found ownername. The caller must ldns_rdf_deep_free it. * \return a status msg describing an error or LDNS_STATUS_OK */ ldns_status ldns_rr_new_question_frm_str(ldns_rr **n, const char *str, ldns_rdf *origin, ldns_rdf **prev); /** * creates a new rr from a file containing a string. * \param[out] rr the new rr * \param[in] fp the file pointer to use * \param[in] default_ttl pointer to a default ttl for the rr. If NULL DEF_TTL will be used * the pointer will be updated if the file contains a $TTL directive * \param[in] origin when the owner is relative add this * the pointer will be updated if the file contains a $ORIGIN directive * The caller must ldns_rdf_deep_free it. * \param[in] prev when the owner is whitespaces use this as the * ownername * the pointer will be updated after the call * The caller must ldns_rdf_deep_free it. * \return a ldns_status with an error or LDNS_STATUS_OK */ ldns_status ldns_rr_new_frm_fp(ldns_rr **rr, FILE *fp, uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev); /** * creates a new rr from a file containing a string. * \param[out] rr the new rr * \param[in] fp the file pointer to use * \param[in] default_ttl a default ttl for the rr. If NULL DEF_TTL will be used * the pointer will be updated if the file contains a $TTL directive * \param[in] origin when the owner is relative add this * the pointer will be updated if the file contains a $ORIGIN directive * The caller must ldns_rdf_deep_free it. * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes) * \param[in] prev when the owner is whitespaces use this as the * ownername * the pointer will be updated after the call * The caller must ldns_rdf_deep_free it. * \return a ldns_status with an error or LDNS_STATUS_OK */ ldns_status ldns_rr_new_frm_fp_l(ldns_rr **rr, FILE *fp, uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev, int *line_nr); /** * sets the owner in the rr structure. * \param[in] *rr rr to operate on * \param[in] *owner set to this owner * \return void */ void ldns_rr_set_owner(ldns_rr *rr, ldns_rdf *owner); /** * sets the question flag in the rr structure. * \param[in] *rr rr to operate on * \param[in] question question flag * \return void */ void ldns_rr_set_question(ldns_rr *rr, bool question); /** * sets the ttl in the rr structure. * \param[in] *rr rr to operate on * \param[in] ttl set to this ttl * \return void */ void ldns_rr_set_ttl(ldns_rr *rr, uint32_t ttl); /** * sets the rd_count in the rr. * \param[in] *rr rr to operate on * \param[in] count set to this count * \return void */ void ldns_rr_set_rd_count(ldns_rr *rr, size_t count); /** * sets the type in the rr. * \param[in] *rr rr to operate on * \param[in] rr_type set to this type * \return void */ void ldns_rr_set_type(ldns_rr *rr, ldns_rr_type rr_type); /** * sets the class in the rr. * \param[in] *rr rr to operate on * \param[in] rr_class set to this class * \return void */ void ldns_rr_set_class(ldns_rr *rr, ldns_rr_class rr_class); /** * sets a rdf member, it will be set on the * position given. The old value is returned, like pop. * \param[in] *rr the rr to operate on * \param[in] *f the rdf to set * \param[in] position the position the set the rdf * \return the old value in the rr, NULL on failyre */ ldns_rdf* ldns_rr_set_rdf(ldns_rr *rr, const ldns_rdf *f, size_t position); /** * sets rd_field member, it will be * placed in the next available spot. * \param[in] *rr rr to operate on * \param[in] *f the data field member to set * \return bool */ bool ldns_rr_push_rdf(ldns_rr *rr, const ldns_rdf *f); /** * removes a rd_field member, it will be * popped from the last position. * \param[in] *rr rr to operate on * \return rdf which was popped (null if nothing) */ ldns_rdf* ldns_rr_pop_rdf(ldns_rr *rr); /** * returns the rdata field member counter. * \param[in] *rr rr to operate on * \param[in] nr the number of the rdf to return * \return ldns_rdf * */ ldns_rdf* ldns_rr_rdf(const ldns_rr *rr, size_t nr); /** * returns the owner name of an rr structure. * \param[in] *rr rr to operate on * \return ldns_rdf * */ ldns_rdf* ldns_rr_owner(const ldns_rr *rr); /** * returns the question flag of an rr structure. * \param[in] *rr rr to operate on * \return bool true if question */ bool ldns_rr_is_question(const ldns_rr *rr); /** * returns the ttl of an rr structure. * \param[in] *rr the rr to read from * \return the ttl of the rr */ uint32_t ldns_rr_ttl(const ldns_rr *rr); /** * returns the rd_count of an rr structure. * \param[in] *rr the rr to read from * \return the rd count of the rr */ size_t ldns_rr_rd_count(const ldns_rr *rr); /** * returns the type of the rr. * \param[in] *rr the rr to read from * \return the type of the rr */ ldns_rr_type ldns_rr_get_type(const ldns_rr *rr); /** * returns the class of the rr. * \param[in] *rr the rr to read from * \return the class of the rr */ ldns_rr_class ldns_rr_get_class(const ldns_rr *rr); /* rr_lists */ /** * returns the number of rr's in an rr_list. * \param[in] rr_list the rr_list to read from * \return the number of rr's */ size_t ldns_rr_list_rr_count(const ldns_rr_list *rr_list); /** * sets the number of rr's in an rr_list. * \param[in] rr_list the rr_list to set the count on * \param[in] count the number of rr in this list * \return void */ void ldns_rr_list_set_rr_count(ldns_rr_list *rr_list, size_t count); /** * set a rr on a specific index in a ldns_rr_list * \param[in] rr_list the rr_list to use * \param[in] r the rr to set * \param[in] count index into the rr_list * \return the old rr which was stored in the rr_list, or * NULL is the index was too large * set a specific rr */ ldns_rr * ldns_rr_list_set_rr(ldns_rr_list *rr_list, const ldns_rr *r, size_t count); /** * returns a specific rr of an rrlist. * \param[in] rr_list the rr_list to read from * \param[in] nr return this rr * \return the rr at position nr */ ldns_rr* ldns_rr_list_rr(const ldns_rr_list *rr_list, size_t nr); /** * creates a new rr_list structure. * \return a new rr_list structure */ ldns_rr_list* ldns_rr_list_new(void); /** * frees an rr_list structure. * \param[in] rr_list the list to free */ void ldns_rr_list_free(ldns_rr_list *rr_list); /** * frees an rr_list structure and all rrs contained therein. * \param[in] rr_list the list to free */ void ldns_rr_list_deep_free(ldns_rr_list *rr_list); /** * concatenates two ldns_rr_lists together. This modifies * *left (to extend it and add the pointers from *right). * \param[in] left the leftside * \param[in] right the rightside * \return a left with right concatenated to it */ bool ldns_rr_list_cat(ldns_rr_list *left, ldns_rr_list *right); /** * concatenates two ldns_rr_lists together, but makes clones of the rr's * (instead of pointer copying). * \param[in] left the leftside * \param[in] right the rightside * \return a new rr_list with leftside/rightside concatenated */ ldns_rr_list* ldns_rr_list_cat_clone(ldns_rr_list *left, ldns_rr_list *right); /** * pushes an rr to an rrlist. * \param[in] rr_list the rr_list to push to * \param[in] rr the rr to push * \return false on error, otherwise true */ bool ldns_rr_list_push_rr(ldns_rr_list *rr_list, const ldns_rr *rr); /** * pushes an rr_list to an rrlist. * \param[in] rr_list the rr_list to push to * \param[in] push_list the rr_list to push * \return false on error, otherwise true */ bool ldns_rr_list_push_rr_list(ldns_rr_list *rr_list, const ldns_rr_list *push_list); /** * pops the last rr from an rrlist. * \param[in] rr_list the rr_list to pop from * \return NULL if nothing to pop. Otherwise the popped RR */ ldns_rr* ldns_rr_list_pop_rr(ldns_rr_list *rr_list); /** * pops an rr_list of size s from an rrlist. * \param[in] rr_list the rr_list to pop from * \param[in] size the number of rr's to pop * \return NULL if nothing to pop. Otherwise the popped rr_list */ ldns_rr_list* ldns_rr_list_pop_rr_list(ldns_rr_list *rr_list, size_t size); /** * returns true if the given rr is one of the rrs in the * list, or if it is equal to one * \param[in] rr_list the rr_list to check * \param[in] rr the rr to check * \return true if rr_list contains rr, false otherwise */ bool ldns_rr_list_contains_rr(const ldns_rr_list *rr_list, ldns_rr *rr); /** * checks if an rr_list is a rrset. * \param[in] rr_list the rr_list to check * \return true if it is an rrset otherwise false */ bool ldns_is_rrset(ldns_rr_list *rr_list); /** * pushes an rr to an rrset (which really are rr_list's). * \param[in] *rr_list the rrset to push the rr to * \param[in] *rr the rr to push * \return true if the push succeeded otherwise false */ bool ldns_rr_set_push_rr(ldns_rr_list *rr_list, ldns_rr *rr); /** * pops the last rr from an rrset. This function is there only * for the symmetry. * \param[in] rr_list the rr_list to pop from * \return NULL if nothing to pop. Otherwise the popped RR * */ ldns_rr* ldns_rr_set_pop_rr(ldns_rr_list *rr_list); /** * pops the first rrset from the list, * the list must be sorted, so that all rr's from each rrset * are next to each other */ ldns_rr_list *ldns_rr_list_pop_rrset(ldns_rr_list *rr_list); /** * retrieves a rrtype by looking up its name. * \param[in] name a string with the name * \return the type which corresponds with the name */ ldns_rr_type ldns_get_rr_type_by_name(const char *name); /** * retrieves a class by looking up its name. * \param[in] name string with the name * \return the cass which corresponds with the name */ ldns_rr_class ldns_get_rr_class_by_name(const char *name); /** * clones a rr and all its data * \param[in] rr the rr to clone * \return the new rr or NULL on failure */ ldns_rr* ldns_rr_clone(const ldns_rr *rr); /** * clones an rrlist. * \param[in] rrlist the rrlist to clone * \return the cloned rr list */ ldns_rr_list* ldns_rr_list_clone(const ldns_rr_list *rrlist); /** * sorts an rr_list (canonical wire format). the sorting is done inband. * \param[in] unsorted the rr_list to be sorted * \return void */ void ldns_rr_list_sort(ldns_rr_list *unsorted); /** * compares two rrs. The TTL is not looked at. * \param[in] rr1 the first one * \param[in] rr2 the second one * \return 0 if equal * -1 if rr1 comes before rr2 * +1 if rr2 comes before rr1 */ int ldns_rr_compare(const ldns_rr *rr1, const ldns_rr *rr2); /** * compares two rrs, up to the rdata. * \param[in] rr1 the first one * \param[in] rr2 the second one * \return 0 if equal * -1 if rr1 comes before rr2 * +1 if rr2 comes before rr1 */ int ldns_rr_compare_no_rdata(const ldns_rr *rr1, const ldns_rr *rr2); /** * compares the wireformat of two rrs, contained in the given buffers. * \param[in] rr1_buf the first one * \param[in] rr2_buf the second one * \return 0 if equal * -1 if rr1_buf comes before rr2_buf * +1 if rr2_buf comes before rr1_buf */ int ldns_rr_compare_wire(ldns_buffer *rr1_buf, ldns_buffer *rr2_buf); /** * returns true of the given rr's are equal. * Also returns true if one record is a DS that represents the * same DNSKEY record as the other record * \param[in] rr1 the first rr * \param[in] rr2 the second rr * \return true if equal otherwise false */ bool ldns_rr_compare_ds(const ldns_rr *rr1, const ldns_rr *rr2); /** * compares two rr listss. * \param[in] rrl1 the first one * \param[in] rrl2 the second one * \return 0 if equal * -1 if rrl1 comes before rrl2 * +1 if rrl2 comes before rrl1 */ int ldns_rr_list_compare(const ldns_rr_list *rrl1, const ldns_rr_list *rrl2); /** * calculates the uncompressed size of an RR. * \param[in] r the rr to operate on * \return size of the rr */ size_t ldns_rr_uncompressed_size(const ldns_rr *r); /** * converts each dname in a rr to its canonical form. * \param[in] rr the rr to work on * \return void */ void ldns_rr2canonical(ldns_rr *rr); /** * converts each dname in each rr in a rr_list to its canonical form. * \param[in] rr_list the rr_list to work on * \return void */ void ldns_rr_list2canonical(ldns_rr_list *rr_list); /** * counts the number of labels of the ownername. * \param[in] rr count the labels of this rr * \return the number of labels */ uint8_t ldns_rr_label_count(ldns_rr *rr); /** * returns the resource record descriptor for the given rr type. * * \param[in] type the type value of the rr type *\return the ldns_rr_descriptor for this type */ const ldns_rr_descriptor *ldns_rr_descript(uint16_t type); /** * returns the minimum number of rdata fields of the rr type this descriptor describes. * * \param[in] descriptor for an rr type * \return the minimum number of rdata fields */ size_t ldns_rr_descriptor_minimum(const ldns_rr_descriptor *descriptor); /** * returns the maximum number of rdata fields of the rr type this descriptor describes. * * \param[in] descriptor for an rr type * \return the maximum number of rdata fields */ size_t ldns_rr_descriptor_maximum(const ldns_rr_descriptor *descriptor); /** * returns the rdf type for the given rdata field number of the rr type for the given descriptor. * * \param[in] descriptor for an rr type * \param[in] field the field number * \return the rdf type for the field */ ldns_rdf_type ldns_rr_descriptor_field_type(const ldns_rr_descriptor *descriptor, size_t field); /** * Return the rr_list which matches the rdf at position field. Think * type-covered stuff for RRSIG * * \param[in] l the rr_list to look in * \param[in] r the rdf to use for the comparison * \param[in] pos at which position can we find the rdf * * \return a new rr list with only the RRs that match * */ ldns_rr_list *ldns_rr_list_subtype_by_rdf(ldns_rr_list *l, ldns_rdf *r, size_t pos); /** * convert an rdf of type LDNS_RDF_TYPE_TYPE to an actual * LDNS_RR_TYPE. This is usefull in the case when inspecting * the rrtype covered field of an RRSIG. * \param[in] rd the rdf to look at * \return a ldns_rr_type with equivalent LDNS_RR_TYPE * */ ldns_rr_type ldns_rdf2rr_type(const ldns_rdf *rd); /** * Returns the type of the first element of the RR * If there are no elements present, 0 is returned * * \param[in] rr_list The rr list * \return rr_type of the first element, or 0 if the list is empty */ ldns_rr_type ldns_rr_list_type(const ldns_rr_list *rr_list); /** * Returns the owner domain name rdf of the first element of the RR * If there are no elements present, NULL is returned * * \param[in] rr_list The rr list * \return dname of the first element, or NULL if the list is empty */ ldns_rdf * ldns_rr_list_owner(const ldns_rr_list *rr_list); #ifdef __cplusplus } #endif #endif /* LDNS_RR_H */ Net-LDNS-0.75/include/ldns/rr_functions.h000644 000770 000024 00000027561 12471046240 020576 0ustar00calledstaff000000 000000 /* * rr_functions.h * * the .h file with defs for the per rr * functions * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ #ifndef LDNS_RR_FUNCTIONS_H #define LDNS_RR_FUNCTIONS_H #ifdef __cplusplus extern "C" { #endif /** * \file * * Defines some extra convenience functions for ldns_rr structures */ /* A / AAAA */ /** * returns the address of a LDNS_RR_TYPE_A rr * \param[in] r the resource record * \return a ldns_rdf* with the address or NULL on failure */ ldns_rdf* ldns_rr_a_address(const ldns_rr *r); /** * sets the address of a LDNS_RR_TYPE_A rr * \param[in] r the rr to use * \param[in] f the address to set * \return true on success, false otherwise */ bool ldns_rr_a_set_address(ldns_rr *r, ldns_rdf *f); /* NS */ /** * returns the name of a LDNS_RR_TYPE_NS rr * \param[in] r the resource record * \return a ldns_rdf* with the name or NULL on failure */ ldns_rdf* ldns_rr_ns_nsdname(const ldns_rr *r); /* MX */ /** * returns the mx pref. of a LDNS_RR_TYPE_MX rr * \param[in] r the resource record * \return a ldns_rdf* with the preference or NULL on failure */ ldns_rdf* ldns_rr_mx_preference(const ldns_rr *r); /** * returns the mx host of a LDNS_RR_TYPE_MX rr * \param[in] r the resource record * \return a ldns_rdf* with the name of the MX host or NULL on failure */ ldns_rdf* ldns_rr_mx_exchange(const ldns_rr *r); /* RRSIG */ /** * returns the type covered of a LDNS_RR_TYPE_RRSIG rr * \param[in] r the resource record * \return a ldns_rdf* with the type covered or NULL on failure */ ldns_rdf* ldns_rr_rrsig_typecovered(const ldns_rr *r); /** * sets the typecovered of a LDNS_RR_TYPE_RRSIG rr * \param[in] r the rr to use * \param[in] f the typecovered to set * \return true on success, false otherwise */ bool ldns_rr_rrsig_set_typecovered(ldns_rr *r, ldns_rdf *f); /** * returns the algorithm of a LDNS_RR_TYPE_RRSIG RR * \param[in] r the resource record * \return a ldns_rdf* with the algorithm or NULL on failure */ ldns_rdf* ldns_rr_rrsig_algorithm(const ldns_rr *r); /** * sets the algorithm of a LDNS_RR_TYPE_RRSIG rr * \param[in] r the rr to use * \param[in] f the algorithm to set * \return true on success, false otherwise */ bool ldns_rr_rrsig_set_algorithm(ldns_rr *r, ldns_rdf *f); /** * returns the number of labels of a LDNS_RR_TYPE_RRSIG RR * \param[in] r the resource record * \return a ldns_rdf* with the number of labels or NULL on failure */ ldns_rdf *ldns_rr_rrsig_labels(const ldns_rr *r); /** * sets the number of labels of a LDNS_RR_TYPE_RRSIG rr * \param[in] r the rr to use * \param[in] f the number of labels to set * \return true on success, false otherwise */ bool ldns_rr_rrsig_set_labels(ldns_rr *r, ldns_rdf *f); /** * returns the original TTL of a LDNS_RR_TYPE_RRSIG RR * \param[in] r the resource record * \return a ldns_rdf* with the original TTL or NULL on failure */ ldns_rdf* ldns_rr_rrsig_origttl(const ldns_rr *r); /** * sets the original TTL of a LDNS_RR_TYPE_RRSIG rr * \param[in] r the rr to use * \param[in] f the original TTL to set * \return true on success, false otherwise */ bool ldns_rr_rrsig_set_origttl(ldns_rr *r, ldns_rdf *f); /** * returns the expiration time of a LDNS_RR_TYPE_RRSIG RR * \param[in] r the resource record * \return a ldns_rdf* with the expiration time or NULL on failure */ ldns_rdf* ldns_rr_rrsig_expiration(const ldns_rr *r); /** * sets the expireation date of a LDNS_RR_TYPE_RRSIG rr * \param[in] r the rr to use * \param[in] f the expireation date to set * \return true on success, false otherwise */ bool ldns_rr_rrsig_set_expiration(ldns_rr *r, ldns_rdf *f); /** * returns the inception time of a LDNS_RR_TYPE_RRSIG RR * \param[in] r the resource record * \return a ldns_rdf* with the inception time or NULL on failure */ ldns_rdf* ldns_rr_rrsig_inception(const ldns_rr *r); /** * sets the inception date of a LDNS_RR_TYPE_RRSIG rr * \param[in] r the rr to use * \param[in] f the inception date to set * \return true on success, false otherwise */ bool ldns_rr_rrsig_set_inception(ldns_rr *r, ldns_rdf *f); /** * returns the keytag of a LDNS_RR_TYPE_RRSIG RR * \param[in] r the resource record * \return a ldns_rdf* with the keytag or NULL on failure */ ldns_rdf* ldns_rr_rrsig_keytag(const ldns_rr *r); /** * sets the keytag of a LDNS_RR_TYPE_RRSIG rr * \param[in] r the rr to use * \param[in] f the keytag to set * \return true on success, false otherwise */ bool ldns_rr_rrsig_set_keytag(ldns_rr *r, ldns_rdf *f); /** * returns the signers name of a LDNS_RR_TYPE_RRSIG RR * \param[in] r the resource record * \return a ldns_rdf* with the signers name or NULL on failure */ ldns_rdf* ldns_rr_rrsig_signame(const ldns_rr *r); /** * sets the signers name of a LDNS_RR_TYPE_RRSIG rr * \param[in] r the rr to use * \param[in] f the signers name to set * \return true on success, false otherwise */ bool ldns_rr_rrsig_set_signame(ldns_rr *r, ldns_rdf *f); /** * returns the signature data of a LDNS_RR_TYPE_RRSIG RR * \param[in] r the resource record * \return a ldns_rdf* with the signature data or NULL on failure */ ldns_rdf* ldns_rr_rrsig_sig(const ldns_rr *r); /** * sets the signature data of a LDNS_RR_TYPE_RRSIG rr * \param[in] r the rr to use * \param[in] f the signature data to set * \return true on success, false otherwise */ bool ldns_rr_rrsig_set_sig(ldns_rr *r, ldns_rdf *f); /* DNSKEY */ /** * returns the flags of a LDNS_RR_TYPE_DNSKEY rr * \param[in] r the resource record * \return a ldns_rdf* with the flags or NULL on failure */ ldns_rdf* ldns_rr_dnskey_flags(const ldns_rr *r); /** * sets the flags of a LDNS_RR_TYPE_DNSKEY rr * \param[in] r the rr to use * \param[in] f the flags to set * \return true on success, false otherwise */ bool ldns_rr_dnskey_set_flags(ldns_rr *r, ldns_rdf *f); /** * returns the protocol of a LDNS_RR_TYPE_DNSKEY rr * \param[in] r the resource record * \return a ldns_rdf* with the protocol or NULL on failure */ ldns_rdf* ldns_rr_dnskey_protocol(const ldns_rr *r); /** * sets the protocol of a LDNS_RR_TYPE_DNSKEY rr * \param[in] r the rr to use * \param[in] f the protocol to set * \return true on success, false otherwise */ bool ldns_rr_dnskey_set_protocol(ldns_rr *r, ldns_rdf *f); /** * returns the algorithm of a LDNS_RR_TYPE_DNSKEY rr * \param[in] r the resource record * \return a ldns_rdf* with the algorithm or NULL on failure */ ldns_rdf* ldns_rr_dnskey_algorithm(const ldns_rr *r); /** * sets the algorithm of a LDNS_RR_TYPE_DNSKEY rr * \param[in] r the rr to use * \param[in] f the algorithm to set * \return true on success, false otherwise */ bool ldns_rr_dnskey_set_algorithm(ldns_rr *r, ldns_rdf *f); /** * returns the key data of a LDNS_RR_TYPE_DNSKEY rr * \param[in] r the resource record * \return a ldns_rdf* with the key data or NULL on failure */ ldns_rdf* ldns_rr_dnskey_key(const ldns_rr *r); /** * sets the key data of a LDNS_RR_TYPE_DNSKEY rr * \param[in] r the rr to use * \param[in] f the key data to set * \return true on success, false otherwise */ bool ldns_rr_dnskey_set_key(ldns_rr *r, ldns_rdf *f); /** * get the length of the keydata in bits * \param[in] keydata the raw key data * \param[in] len the length of the keydata * \param[in] alg the cryptographic algorithm this is a key for * \return the keysize in bits, or 0 on error */ size_t ldns_rr_dnskey_key_size_raw(const unsigned char *keydata, const size_t len, const ldns_algorithm alg); /** * get the length of the keydata in bits * \param[in] key the key rr to use * \return the keysize in bits */ size_t ldns_rr_dnskey_key_size(const ldns_rr *key); /** * The type of function to be passed to ldns_rr_soa_increment_func, * ldns_rr_soa_increment_func_data or ldns_rr_soa_increment_int. * The function will be called with as the first argument the current serial * number of the SOA RR to be updated, and as the second argument a value * given when calling ldns_rr_soa_increment_func_data or * ldns_rr_soa_increment_int. With ldns_rr_soa_increment_int the pointer * value holds the integer value passed to ldns_rr_soa_increment_int, * and it should be cast to intptr_t to be used as an integer by the * serial modifying function. */ typedef uint32_t (*ldns_soa_serial_increment_func_t)(uint32_t, void*); /** * Function to be used with dns_rr_soa_increment_func_int, to set the soa * serial number. * \param[in] unused the (unused) current serial number. * \param[in] data the serial number to be set. */ uint32_t ldns_soa_serial_identity(uint32_t unused, void *data); /** * Function to be used with dns_rr_soa_increment_func, to increment the soa * serial number with one. * \param[in] s the current serial number. * \param[in] unused unused. */ uint32_t ldns_soa_serial_increment(uint32_t s, void *unused); /** * Function to be used with dns_rr_soa_increment_func_int, to increment the soa * serial number with a certain amount. * \param[in] s the current serial number. * \param[in] data the amount to add to the current serial number. */ uint32_t ldns_soa_serial_increment_by(uint32_t s, void *data); /** * Function to be used with ldns_rr_soa_increment_func or * ldns_rr_soa_increment_func_int to set the soa serial to the number of * seconds since unix epoch (1-1-1970 00:00). * When data is given (i.e. the function is called via * ldns_rr_soa_increment_func_int), it is used as the current time. * When the resulting serial number is smaller than the current serial number, * the current serial number is increased by one. * \param[in] s the current serial number. * \param[in] data the time in seconds since 1-1-1970 00:00 */ uint32_t ldns_soa_serial_unixtime(uint32_t s, void *data); /** * Function to be used with ldns_rr_soa_increment_func or * ldns_rr_soa_increment_func_int to set the soa serial to the current date * succeeded by a two digit iteration (datecounter). * When data is given (i.e. the function is called via * ldns_rr_soa_increment_func_int), it is used as the current time. * When the resulting serial number is smaller than the current serial number, * the current serial number is increased by one. * \param[in] s the current serial number. * \param[in] data the time in seconds since 1-1-1970 00:00 */ uint32_t ldns_soa_serial_datecounter(uint32_t s, void *data); /** * Increment the serial number of the given SOA by one. * \param[in] soa The soa rr to be incremented */ void ldns_rr_soa_increment( ldns_rr *soa); /** * Increment the serial number of the given SOA with the given function. * Included functions to be used here are: ldns_rr_soa_increment, * ldns_soa_serial_unixtime and ldns_soa_serial_datecounter. * \param[in] soa The soa rr to be incremented * \param[in] f the function to use to increment the soa rr. */ void ldns_rr_soa_increment_func( ldns_rr *soa, ldns_soa_serial_increment_func_t f); /** * Increment the serial number of the given SOA with the given function * passing it the given data argument. * \param[in] soa The soa rr to be incremented * \param[in] f the function to use to increment the soa rr. * \param[in] data this argument will be passed to f as the second argument. */ void ldns_rr_soa_increment_func_data( ldns_rr *soa, ldns_soa_serial_increment_func_t f, void *data); /** * Increment the serial number of the given SOA with the given function * using data as an argument for the function. * Included functions to be used here are: ldns_soa_serial_identity, * ldns_rr_soa_increment_by, ldns_soa_serial_unixtime and * ldns_soa_serial_datecounter. * \param[in] soa The soa rr to be incremented * \param[in] f the function to use to increment the soa rr. * \param[in] data this argument will be passed to f as the second argument * (by casting it to void*). */ void ldns_rr_soa_increment_func_int( ldns_rr *soa, ldns_soa_serial_increment_func_t f, int data); #ifdef __cplusplus } #endif #endif /* LDNS_RR_FUNCTIONS_H */ Net-LDNS-0.75/include/ldns/sha1.h000644 000770 000024 00000002215 12471046240 016704 0ustar00calledstaff000000 000000 #ifndef LDNS_SHA1_H #define LDNS_SHA1_H #ifdef __cplusplus extern "C" { #endif #define LDNS_SHA1_BLOCK_LENGTH 64 #define LDNS_SHA1_DIGEST_LENGTH 20 typedef struct { uint32_t state[5]; uint64_t count; unsigned char buffer[LDNS_SHA1_BLOCK_LENGTH]; } ldns_sha1_ctx; void ldns_sha1_init(ldns_sha1_ctx * context); void ldns_sha1_transform(uint32_t state[5], const unsigned char buffer[LDNS_SHA1_BLOCK_LENGTH]); void ldns_sha1_update(ldns_sha1_ctx *context, const unsigned char *data, unsigned int len); void ldns_sha1_final(unsigned char digest[LDNS_SHA1_DIGEST_LENGTH], ldns_sha1_ctx *context); /** * Convenience function to digest a fixed block of data at once. * * \param[in] data the data to digest * \param[in] data_len the length of data in bytes * \param[out] digest the length of data in bytes * This pointer MUST have LDNS_SHA1_DIGEST_LENGTH bytes * available * \return the SHA1 digest of the given data */ unsigned char *ldns_sha1(unsigned char *data, unsigned int data_len, unsigned char *digest); #ifdef __cplusplus } #endif #endif /* LDNS_SHA1_H */ Net-LDNS-0.75/include/ldns/sha2.h000644 000770 000024 00000012612 12471046240 016707 0ustar00calledstaff000000 000000 /* * FILE: sha2.h * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ * * Copyright (c) 2000-2001, Aaron D. Gifford * All rights reserved. * * Modified by Jelte Jansen to fit in ldns, and not clash with any * system-defined SHA code. * Changes: * - Renamed (external) functions and constants to fit ldns style * - Removed uintXX vs. u_intXX smartness, since ldns needs uintXX * anyway * - BYTE ORDER check replaced by simple ifdef as defined or not by * configure.ac * - Removed _End and _Data functions * - Added ldns_shaX(data, len, digest) functions * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ */ #ifndef __LDNS_SHA2_H__ #define __LDNS_SHA2_H__ #ifdef __cplusplus extern "C" { #endif /* * Import u_intXX_t size_t type definitions from system headers. You * may need to change this, or define these things yourself in this * file. */ #include #if LDNS_BUILD_CONFIG_HAVE_INTTYPES_H #include #endif /* LDNS_BUILD_CONFIG_HAVE_INTTYPES_H */ /*** SHA-256/384/512 Various Length Definitions ***********************/ #define LDNS_SHA256_BLOCK_LENGTH 64 #define LDNS_SHA256_DIGEST_LENGTH 32 #define LDNS_SHA256_DIGEST_STRING_LENGTH (LDNS_SHA256_DIGEST_LENGTH * 2 + 1) #define LDNS_SHA384_BLOCK_LENGTH 128 #define LDNS_SHA384_DIGEST_LENGTH 48 #define LDNS_SHA384_DIGEST_STRING_LENGTH (LDNS_SHA384_DIGEST_LENGTH * 2 + 1) #define LDNS_SHA512_BLOCK_LENGTH 128 #define LDNS_SHA512_DIGEST_LENGTH 64 #define LDNS_SHA512_DIGEST_STRING_LENGTH (LDNS_SHA512_DIGEST_LENGTH * 2 + 1) /*** SHA-256/384/512 Context Structures *******************************/ typedef struct _ldns_sha256_CTX { uint32_t state[8]; uint64_t bitcount; uint8_t buffer[LDNS_SHA256_BLOCK_LENGTH]; } ldns_sha256_CTX; typedef struct _ldns_sha512_CTX { uint64_t state[8]; uint64_t bitcount[2]; uint8_t buffer[LDNS_SHA512_BLOCK_LENGTH]; } ldns_sha512_CTX; typedef ldns_sha512_CTX ldns_sha384_CTX; /*** SHA-256/384/512 Function Prototypes ******************************/ void ldns_sha256_init(ldns_sha256_CTX *); void ldns_sha256_update(ldns_sha256_CTX*, const uint8_t*, size_t); void ldns_sha256_final(uint8_t[LDNS_SHA256_DIGEST_LENGTH], ldns_sha256_CTX*); void ldns_sha384_init(ldns_sha384_CTX*); void ldns_sha384_update(ldns_sha384_CTX*, const uint8_t*, size_t); void ldns_sha384_final(uint8_t[LDNS_SHA384_DIGEST_LENGTH], ldns_sha384_CTX*); void ldns_sha512_init(ldns_sha512_CTX*); void ldns_sha512_update(ldns_sha512_CTX*, const uint8_t*, size_t); void ldns_sha512_final(uint8_t[LDNS_SHA512_DIGEST_LENGTH], ldns_sha512_CTX*); /** * Convenience function to digest a fixed block of data at once. * * \param[in] data the data to digest * \param[in] data_len the length of data in bytes * \param[out] digest the length of data in bytes * This pointer MUST have LDNS_SHA256_DIGEST_LENGTH bytes * available * \return the SHA1 digest of the given data */ unsigned char *ldns_sha256(unsigned char *data, unsigned int data_len, unsigned char *digest); /** * Convenience function to digest a fixed block of data at once. * * \param[in] data the data to digest * \param[in] data_len the length of data in bytes * \param[out] digest the length of data in bytes * This pointer MUST have LDNS_SHA384_DIGEST_LENGTH bytes * available * \return the SHA1 digest of the given data */ unsigned char *ldns_sha384(unsigned char *data, unsigned int data_len, unsigned char *digest); /** * Convenience function to digest a fixed block of data at once. * * \param[in] data the data to digest * \param[in] data_len the length of data in bytes * \param[out] digest the length of data in bytes * This pointer MUST have LDNS_SHA512_DIGEST_LENGTH bytes * available * \return the SHA1 digest of the given data */ unsigned char *ldns_sha512(unsigned char *data, unsigned int data_len, unsigned char *digest); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __LDNS_SHA2_H__ */ Net-LDNS-0.75/include/ldns/str2host.h000644 000770 000024 00000022063 12471046240 017643 0ustar00calledstaff000000 000000 /** * str2host.h - conversion from str to the host fmt * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ #ifndef LDNS_2HOST_H #define LDNS_2HOST_H #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * \file * * Defines functions to convert dns data in presentation format or text files * to internal structures. */ /** * convert a byte into wireformat * \param[in] rd the rdf where to put the data * \param[in] bytestr the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_int8(ldns_rdf **rd, const char *bytestr); /** * convert a string to a int16 in wireformat * \param[in] rd the rdf where to put the data * \param[in] shortstr the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_int16(ldns_rdf **rd, const char *shortstr); /** * convert a strings into a 4 byte int in wireformat * \param[in] rd the rdf where to put the data * \param[in] longstr the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_int32(ldns_rdf **rd, const char *longstr); /** * convert a time string to a time value in wireformat * \param[in] rd the rdf where to put the data * \param[in] time the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_time(ldns_rdf **rd, const char *time); /* convert string with NSEC3 salt to wireformat) * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * return ldns_status */ ldns_status ldns_str2rdf_nsec3_salt(ldns_rdf **rd, const char *nsec3_salt); /* convert a time period (think TTL's) to wireformat) * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * return ldns_status */ ldns_status ldns_str2rdf_period(ldns_rdf **rd, const char *str); /** * convert str with an A record into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_a(ldns_rdf **rd, const char *str); /** * convert the str with an AAAA record into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_aaaa(ldns_rdf **rd, const char *str); /** * convert a string into wireformat (think txt record) * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted (NULL terminated) * \return ldns_status */ ldns_status ldns_str2rdf_str(ldns_rdf **rd, const char *str); /** * convert str with the apl record into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_apl(ldns_rdf **rd, const char *str); /** * convert the string with the b64 data into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_b64(ldns_rdf **rd, const char *str); /** * convert the string with the b32 ext hex data into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_b32_ext(ldns_rdf **rd, const char *str); /** * convert a hex value into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_hex(ldns_rdf **rd, const char *str); /** * convert string with nsec into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_nsec(ldns_rdf **rd, const char *str); /** * convert a rrtype into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_type(ldns_rdf **rd, const char *str); /** * convert string with a classname into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_class(ldns_rdf **rd, const char *str); /** * convert an certificate algorithm value into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_cert_alg(ldns_rdf **rd, const char *str); /** * convert an algorithm value into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_alg(ldns_rdf **rd, const char *str); /** * convert a tlsa certificate usage value into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_certificate_usage(ldns_rdf **rd, const char *str); /** * convert a tlsa selector value into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_selector(ldns_rdf **rd, const char *str); /** * convert a tlsa matching type value into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_matching_type(ldns_rdf **rd, const char *str); /** * convert a string with a unknown RR into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_unknown(ldns_rdf **rd, const char *str); /** * convert string with a protocol service into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_service(ldns_rdf **rd, const char *str); /** * convert a string with a LOC RR into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_loc(ldns_rdf **rd, const char *str); /** * convert string with a WKS RR into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_wks(ldns_rdf **rd, const char *str); /** * convert a str with a NSAP RR into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_nsap(ldns_rdf **rd, const char *str); /** * convert a str with a ATMA RR into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_atma(ldns_rdf **rd, const char *str); /** * convert a str with a IPSECKEY RR into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_ipseckey(ldns_rdf **rd, const char *str); /** * convert a dname string into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_dname(ldns_rdf **rd, const char *str); /** * convert 4 * 16bit hex separated by colons into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_ilnp64(ldns_rdf **rd, const char *str); /** * convert 6 hex bytes separated by dashes into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_eui48(ldns_rdf **rd, const char *str); /** * convert 8 hex bytes separated by dashes into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_eui64(ldns_rdf **rd, const char *str); /** * Convert a non-zero sequence of US-ASCII letters and numbers into wireformat * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_tag(ldns_rdf **rd, const char *str); /** * Convert a encoding of the value field as specified * [RFC1035], Section 5.1., encoded as one bug chunk of data. * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_long_str(ldns_rdf **rd, const char *str); /** * Convert a " " encoding of the value field as specified * in Section 6. of [RFC5205], encoded as wireformat as specified in Section 5. * of [RFC5205]. * \param[in] rd the rdf where to put the data * \param[in] str the string to be converted * \return ldns_status */ ldns_status ldns_str2rdf_hip(ldns_rdf **rd, const char *str); #ifdef __cplusplus } #endif #endif /* LDNS_2HOST_H */ Net-LDNS-0.75/include/ldns/tsig.h000644 000770 000024 00000007324 12471046240 017024 0ustar00calledstaff000000 000000 /* * tsig.h -- defines for TSIG [RFC2845] * * Copyright (c) 2005-2008, NLnet Labs. All rights reserved. * * See LICENSE for the license. */ #ifndef LDNS_TSIG_H #define LDNS_TSIG_H #ifdef __cplusplus extern "C" { #endif /** * \file * * Defines functions for TSIG usage */ /** * Contains credentials for TSIG */ typedef struct ldns_tsig_credentials_struct { char *algorithm; char *keyname; char *keydata; /* XXX More eventually. */ } ldns_tsig_credentials; char *ldns_tsig_algorithm(ldns_tsig_credentials *); char *ldns_tsig_keyname(ldns_tsig_credentials *); char *ldns_tsig_keydata(ldns_tsig_credentials *); char *ldns_tsig_keyname_clone(ldns_tsig_credentials *); char *ldns_tsig_keydata_clone(ldns_tsig_credentials *); /** * verifies the tsig rr for the given packet and key. * The wire must be given too because tsig does not sign normalized packets. * \param[in] pkt the packet to verify * \param[in] wire needed to verify the mac * \param[in] wire_size size of wire * \param[in] key_name the name of the shared key * \param[in] key_data the key in base 64 format * \param[in] mac original mac * \return true if tsig is correct, false if not, or if tsig is not set */ bool ldns_pkt_tsig_verify(ldns_pkt *pkt, uint8_t *wire, size_t wire_size, const char *key_name, const char *key_data, ldns_rdf *mac); /** * verifies the tsig rr for the given packet and key. * The wire must be given too because tsig does not sign normalized packets. * \param[in] pkt the packet to verify * \param[in] wire needed to verify the mac * \param[in] wire_size size of wire * \param[in] key_name the name of the shared key * \param[in] key_data the key in base 64 format * \param[in] mac original mac * \param[in] tsig_timers_only must be zero for the first packet and positive for subsequent packets. If zero, all digest components are used to verify the _mac. If non-zero, only the TSIG timers are used to verify the mac. * \return true if tsig is correct, false if not, or if tsig is not set */ bool ldns_pkt_tsig_verify_next(ldns_pkt *pkt, uint8_t *wire, size_t wire_size, const char *key_name, const char *key_data, ldns_rdf *mac, int tsig_timers_only); /** * creates a tsig rr for the given packet and key. * \param[in] pkt the packet to sign * \param[in] key_name the name of the shared key * \param[in] key_data the key in base 64 format * \param[in] fudge seconds of error permitted in time signed * \param[in] algorithm_name the name of the algorithm used * \param[in] query_mac is added to the digest if not NULL (so NULL is for signing queries, not NULL is for signing answers) * \return status (OK if success) */ ldns_status ldns_pkt_tsig_sign(ldns_pkt *pkt, const char *key_name, const char *key_data, uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac); /** * creates a tsig rr for the given packet and key. * \param[in] pkt the packet to sign * \param[in] key_name the name of the shared key * \param[in] key_data the key in base 64 format * \param[in] fudge seconds of error permitted in time signed * \param[in] algorithm_name the name of the algorithm used * \param[in] query_mac is added to the digest if not NULL (so NULL is for signing queries, not NULL is for signing answers) * \param[in] tsig_timers_only must be zero for the first packet and positive for subsequent packets. If zero, all digest components are used to create the query_mac. If non-zero, only the TSIG timers are used to create the query_mac. * \return status (OK if success) */ ldns_status ldns_pkt_tsig_sign_next(ldns_pkt *pkt, const char *key_name, const char *key_data, uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac, int tsig_timers_only); #ifdef __cplusplus } #endif #endif /* LDNS_TSIG_H */ Net-LDNS-0.75/include/ldns/update.h000644 000770 000024 00000005245 12471046240 017340 0ustar00calledstaff000000 000000 /* * update.h * * Functions for RFC 2136 Dynamic Update * * Copyright (c) 2005-2008, NLnet Labs. All rights reserved. * * See LICENSE for the license. */ /** * \file * * Defines functions to perform UPDATE queries */ #ifndef LDNS_UPDATE_H #define LDNS_UPDATE_H #include #ifdef __cplusplus extern "C" { #endif /** * create an update packet from zone name, class and the rr lists * \param[in] zone_rdf name of the zone * \param[in] clas zone class * \param[in] pr_rrlist list of Prerequisite Section RRs * \param[in] up_rrlist list of Updates Section RRs * \param[in] ad_rrlist list of Additional Data Section RRs (currently unused) * \return the new packet */ ldns_pkt *ldns_update_pkt_new(ldns_rdf *zone_rdf, ldns_rr_class clas, ldns_rr_list *pr_rrlist, ldns_rr_list *up_rrlist, ldns_rr_list *ad_rrlist); /** * add tsig credentials to * a packet from a resolver * \param[in] p packet to copy to * \param[in] r resolver to copy from * * \return status wether successfull or not */ ldns_status ldns_update_pkt_tsig_add(ldns_pkt *p, ldns_resolver *r); /* access functions */ /** * Get the zo count * \param[in] p the packet * \return the zo count */ uint16_t ldns_update_zocount(const ldns_pkt *p); /** * Get the zo count * \param[in] p the packet * \return the pr count */ uint16_t ldns_update_prcount(const ldns_pkt *p); /** * Get the zo count * \param[in] p the packet * \return the up count */ uint16_t ldns_update_upcount(const ldns_pkt *p); /** * Get the zo count * \param[in] p the packet * \return the ad count */ uint16_t ldns_update_ad(const ldns_pkt *p); /** * Set the zo count * \param[in] p the packet * \param[in] c the zo count to set */ void ldns_update_set_zo(ldns_pkt *p, uint16_t c); /** * Set the pr count * \param[in] p the packet * \param[in] c the pr count to set */ void ldns_update_set_prcount(ldns_pkt *p, uint16_t c); /** * Set the up count * \param[in] p the packet * \param[in] c the up count to set */ void ldns_update_set_upcount(ldns_pkt *p, uint16_t c); /** * Set the ad count * \param[in] p the packet * \param[in] c the ad count to set */ void ldns_update_set_adcount(ldns_pkt *p, uint16_t c); /* soa functions that need to be configured */ /* * Not sure if we want to keep these like this, therefore * not documented */ ldns_status ldns_update_soa_mname(ldns_rdf *zone, ldns_resolver *r, ldns_rr_class c, ldns_rdf **mname); /* * Not sure if we want to keep these like this, therefore * not documented */ ldns_status ldns_update_soa_zone_mname(const char *fqdn, ldns_resolver *r, ldns_rr_class c, ldns_rdf **zone_rdf, ldns_rdf **mname_rdf); #ifdef __cplusplus } #endif #endif /* LDNS_UPDATE_H */ Net-LDNS-0.75/include/ldns/util.h000644 000770 000024 00000024562 12471046240 017036 0ustar00calledstaff000000 000000 /* * util.h * * helper function header file * * a Net::DNS like library for C * * (c) NLnet Labs, 2004 * * See the file LICENSE for the license */ #ifndef _UTIL_H #define _UTIL_H #include "EXTERN.h" #include "perl.h" #include #include #include #ifdef __cplusplus extern "C" { #endif #define dprintf(X,Y) fprintf(stderr, (X), (Y)) /* #define dprintf(X, Y) */ #define LDNS_VERSION "1.6.18" #define LDNS_REVISION ((1<<16)|(6<<8)|(18)) /** * splint static inline workaround */ #ifdef S_SPLINT_S # define INLINE #else # ifdef SWIG # define INLINE static # else # define INLINE static inline # endif #endif /** * Memory management macros */ #define LDNS_MALLOC(type) LDNS_XMALLOC(type, 1) #define LDNS_XMALLOC(type, count) ((type *) malloc((count) * sizeof(type))) #define LDNS_CALLOC(type, count) ((type *) calloc((count), sizeof(type))) #define LDNS_REALLOC(ptr, type) LDNS_XREALLOC((ptr), type, 1) #define LDNS_XREALLOC(ptr, type, count) \ ((type *) realloc((ptr), (count) * sizeof(type))) #define LDNS_FREE(ptr) \ do { free((ptr)); (ptr) = NULL; } while (0) #define LDNS_DEP printf("DEPRECATED FUNCTION!\n"); /* * Copy data allowing for unaligned accesses in network byte order * (big endian). */ INLINE uint16_t ldns_read_uint16(const void *src) { #ifdef ALLOW_UNALIGNED_ACCESSES return ntohs(*(const uint16_t *) src); #else const uint8_t *p = (const uint8_t *) src; return ((uint16_t) p[0] << 8) | (uint16_t) p[1]; #endif } INLINE uint32_t ldns_read_uint32(const void *src) { #ifdef ALLOW_UNALIGNED_ACCESSES return ntohl(*(const uint32_t *) src); #else const uint8_t *p = (const uint8_t *) src; return ( ((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16) | ((uint32_t) p[2] << 8) | (uint32_t) p[3]); #endif } /* * Copy data allowing for unaligned accesses in network byte order * (big endian). */ INLINE void ldns_write_uint16(void *dst, uint16_t data) { #ifdef ALLOW_UNALIGNED_ACCESSES * (uint16_t *) dst = htons(data); #else uint8_t *p = (uint8_t *) dst; p[0] = (uint8_t) ((data >> 8) & 0xff); p[1] = (uint8_t) (data & 0xff); #endif } INLINE void ldns_write_uint32(void *dst, uint32_t data) { #ifdef ALLOW_UNALIGNED_ACCESSES * (uint32_t *) dst = htonl(data); #else uint8_t *p = (uint8_t *) dst; p[0] = (uint8_t) ((data >> 24) & 0xff); p[1] = (uint8_t) ((data >> 16) & 0xff); p[2] = (uint8_t) ((data >> 8) & 0xff); p[3] = (uint8_t) (data & 0xff); #endif } /* warning. */ INLINE void ldns_write_uint64_as_uint48(void *dst, uint64_t data) { uint8_t *p = (uint8_t *) dst; p[0] = (uint8_t) ((data >> 40) & 0xff); p[1] = (uint8_t) ((data >> 32) & 0xff); p[2] = (uint8_t) ((data >> 24) & 0xff); p[3] = (uint8_t) ((data >> 16) & 0xff); p[4] = (uint8_t) ((data >> 8) & 0xff); p[5] = (uint8_t) (data & 0xff); } /** * Structure to do a Schwartzian-like transformation, for instance when * sorting. If you need a transformation on the objects that are sorted, * you can sue this to store the transformed values, so you do not * need to do the transformation again for each comparison */ struct ldns_schwartzian_compare_struct { void *original_object; void *transformed_object; }; /** A general purpose lookup table * * Lookup tables are arrays of (id, name) pairs, * So you can for instance lookup the RCODE 3, which is "NXDOMAIN", * and vice versa. The lookup tables themselves are defined wherever needed, * for instance in \ref host2str.c */ struct ldns_struct_lookup_table { int id; const char *name; }; typedef struct ldns_struct_lookup_table ldns_lookup_table; /** * Looks up the table entry by name, returns NULL if not found. * \param[in] table the lookup table to search in * \param[in] name what to search for * \return the item found */ ldns_lookup_table *ldns_lookup_by_name(ldns_lookup_table table[], const char *name); /** * Looks up the table entry by id, returns NULL if not found. * \param[in] table the lookup table to search in * \param[in] id what to search for * \return the item found */ ldns_lookup_table *ldns_lookup_by_id(ldns_lookup_table table[], int id); /** * Returns the value of the specified bit * The bits are counted from left to right, so bit #0 is the * left most bit. * \param[in] bits array holding the bits * \param[in] index to the wanted bit * \return */ int ldns_get_bit(uint8_t bits[], size_t index); /** * Returns the value of the specified bit * The bits are counted from right to left, so bit #0 is the * right most bit. * \param[in] bits array holding the bits * \param[in] index to the wanted bit * \return 1 or 0 depending no the bit state */ int ldns_get_bit_r(uint8_t bits[], size_t index); /** * sets the specified bit in the specified byte to * 1 if value is true, 0 if false * The bits are counted from right to left, so bit #0 is the * right most bit. * \param[in] byte the bit to set the bit in * \param[in] bit_nr the bit to set (0 <= n <= 7) * \param[in] value whether to set the bit to 1 or 0 * \return 1 or 0 depending no the bit state */ void ldns_set_bit(uint8_t *byte, int bit_nr, bool value); /** * Returns the value of a to the power of b * (or 1 of b < 1) */ /*@unused@*/ INLINE long ldns_power(long a, long b) { long result = 1; while (b > 0) { if (b & 1) { result *= a; if (b == 1) { return result; } } a *= a; b /= 2; } return result; } /** * Returns the int value of the given (hex) digit * \param[in] ch the hex char to convert * \return the converted decimal value */ int ldns_hexdigit_to_int(char ch); /** * Returns the char (hex) representation of the given int * \param[in] ch the int to convert * \return the converted hex char */ char ldns_int_to_hexdigit(int ch); /** * Converts a hex string to binary data * * \param[out] data The binary result is placed here. * At least strlen(str)/2 bytes should be allocated * \param[in] str The hex string to convert. * This string should not contain spaces * \return The number of bytes of converted data, or -1 if one of the arguments * is NULL, or -2 if the string length is not an even number */ int ldns_hexstring_to_data(uint8_t *data, const char *str); /** * Show the internal library version * \return a string with the version in it */ const char * ldns_version(void); /** * Convert TM to seconds since epoch (midnight, January 1st, 1970). * Like timegm(3), which is not always available. * \param[in] tm a struct tm* with the date * \return the seconds since epoch */ time_t ldns_mktime_from_utc(const struct tm *tm); time_t mktime_from_utc(const struct tm *tm); /** * The function interprets time as the number of seconds since epoch * with respect to now using serial arithmitics (rfc1982). * That number of seconds is then converted to broken-out time information. * This is especially usefull when converting the inception and expiration * fields of RRSIG records. * * \param[in] time number of seconds since epoch (midnight, January 1st, 1970) * to be intepreted as a serial arithmitics number relative to now. * \param[in] now number of seconds since epoch (midnight, January 1st, 1970) * to which the time value is compared to determine the final value. * \param[out] result the struct with the broken-out time information * \return result on success or NULL on error */ struct tm * ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result); /** * Seed the random function. * If the file descriptor is specified, the random generator is seeded with * data from that file. If not, /dev/urandom is used. * * applications should call this if they need entropy data within ldns * If openSSL is available, it is automatically seeded from /dev/urandom * or /dev/random. * * If you need more entropy, or have no openssl available, this function * MUST be called at the start of the program * * If openssl *is* available, this function just adds more entropy * * \param[in] fd a file providing entropy data for the seed * \param[in] size the number of bytes to use as entropy data. If this is 0, * only the minimal amount is taken (usually 4 bytes) * \return 0 if seeding succeeds, 1 if it fails */ int ldns_init_random(FILE *fd, unsigned int size); /** * Get random number. * \return random number. * */ uint16_t ldns_get_random(void); /** * Encode data as BubbleBabble * * \param[in] data a pointer to data to be encoded * \param[in] len size the number of bytes of data * \return a string of BubbleBabble */ char *ldns_bubblebabble(uint8_t *data, size_t len); INLINE time_t ldns_time(time_t *t) { return time(t); } /** * calculates the size needed to store the result of b32_ntop */ /*@unused@*/ INLINE size_t ldns_b32_ntop_calculate_size(size_t src_data_length) { return src_data_length == 0 ? 0 : ((src_data_length - 1) / 5 + 1) * 8; } INLINE size_t ldns_b32_ntop_calculate_size_no_padding(size_t src_data_length) { return ((src_data_length + 3) * 8 / 5) - 4; } int ldns_b32_ntop(const uint8_t* src_data, size_t src_data_length, char* target_text_buffer, size_t target_text_buffer_size); int ldns_b32_ntop_extended_hex(const uint8_t* src_data, size_t src_data_length, char* target_text_buffer, size_t target_text_buffer_size); #if ! LDNS_BUILD_CONFIG_HAVE_B32_NTOP int b32_ntop(const uint8_t* src_data, size_t src_data_length, char* target_text_buffer, size_t target_text_buffer_size); int b32_ntop_extended_hex(const uint8_t* src_data, size_t src_data_length, char* target_text_buffer, size_t target_text_buffer_size); #endif /* ! LDNS_BUILD_CONFIG_HAVE_B32_NTOP */ /** * calculates the size needed to store the result of b32_pton */ /*@unused@*/ INLINE size_t ldns_b32_pton_calculate_size(size_t src_text_length) { return src_text_length * 5 / 8; } int ldns_b32_pton(const char* src_text, size_t src_text_length, uint8_t* target_data_buffer, size_t target_data_buffer_size); int ldns_b32_pton_extended_hex(const char* src_text, size_t src_text_length, uint8_t* target_data_buffer, size_t target_data_buffer_size); #if ! LDNS_BUILD_CONFIG_HAVE_B32_PTON int b32_pton(const char* src_text, size_t src_text_length, uint8_t* target_data_buffer, size_t target_data_buffer_size); int b32_pton_extended_hex(const char* src_text, size_t src_text_length, uint8_t* target_data_buffer, size_t target_data_buffer_size); #endif /* ! LDNS_BUILD_CONFIG_HAVE_B32_PTON */ #ifdef __cplusplus } #endif #endif /* !_UTIL_H */ Net-LDNS-0.75/include/ldns/wire2host.h000644 000770 000024 00000016135 12471046240 020004 0ustar00calledstaff000000 000000 /* * wire2host.h - from wire conversion routines * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ /** * \file * * Contains functions that translate dns data from the wire format (as sent * by servers and clients) to the internal structures. */ #ifndef LDNS_WIRE2HOST_H #define LDNS_WIRE2HOST_H #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* The length of the header */ #define LDNS_HEADER_SIZE 12 /* First octet of flags */ #define LDNS_RD_MASK 0x01U #define LDNS_RD_SHIFT 0 #define LDNS_RD_WIRE(wirebuf) (*(wirebuf+2) & LDNS_RD_MASK) #define LDNS_RD_SET(wirebuf) (*(wirebuf+2) |= LDNS_RD_MASK) #define LDNS_RD_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_RD_MASK) #define LDNS_TC_MASK 0x02U #define LDNS_TC_SHIFT 1 #define LDNS_TC_WIRE(wirebuf) (*(wirebuf+2) & LDNS_TC_MASK) #define LDNS_TC_SET(wirebuf) (*(wirebuf+2) |= LDNS_TC_MASK) #define LDNS_TC_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_TC_MASK) #define LDNS_AA_MASK 0x04U #define LDNS_AA_SHIFT 2 #define LDNS_AA_WIRE(wirebuf) (*(wirebuf+2) & LDNS_AA_MASK) #define LDNS_AA_SET(wirebuf) (*(wirebuf+2) |= LDNS_AA_MASK) #define LDNS_AA_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_AA_MASK) #define LDNS_OPCODE_MASK 0x78U #define LDNS_OPCODE_SHIFT 3 #define LDNS_OPCODE_WIRE(wirebuf) ((*(wirebuf+2) & LDNS_OPCODE_MASK) >> LDNS_OPCODE_SHIFT) #define LDNS_OPCODE_SET(wirebuf, opcode) \ (*(wirebuf+2) = ((*(wirebuf+2)) & ~LDNS_OPCODE_MASK) | ((opcode) << LDNS_OPCODE_SHIFT)) #define LDNS_QR_MASK 0x80U #define LDNS_QR_SHIFT 7 #define LDNS_QR_WIRE(wirebuf) (*(wirebuf+2) & LDNS_QR_MASK) #define LDNS_QR_SET(wirebuf) (*(wirebuf+2) |= LDNS_QR_MASK) #define LDNS_QR_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_QR_MASK) /* Second octet of flags */ #define LDNS_RCODE_MASK 0x0fU #define LDNS_RCODE_SHIFT 0 #define LDNS_RCODE_WIRE(wirebuf) (*(wirebuf+3) & LDNS_RCODE_MASK) #define LDNS_RCODE_SET(wirebuf, rcode) \ (*(wirebuf+3) = ((*(wirebuf+3)) & ~LDNS_RCODE_MASK) | (rcode)) #define LDNS_CD_MASK 0x10U #define LDNS_CD_SHIFT 4 #define LDNS_CD_WIRE(wirebuf) (*(wirebuf+3) & LDNS_CD_MASK) #define LDNS_CD_SET(wirebuf) (*(wirebuf+3) |= LDNS_CD_MASK) #define LDNS_CD_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_CD_MASK) #define LDNS_AD_MASK 0x20U #define LDNS_AD_SHIFT 5 #define LDNS_AD_WIRE(wirebuf) (*(wirebuf+3) & LDNS_AD_MASK) #define LDNS_AD_SET(wirebuf) (*(wirebuf+3) |= LDNS_AD_MASK) #define LDNS_AD_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_AD_MASK) #define LDNS_Z_MASK 0x40U #define LDNS_Z_SHIFT 6 #define LDNS_Z_WIRE(wirebuf) (*(wirebuf+3) & LDNS_Z_MASK) #define LDNS_Z_SET(wirebuf) (*(wirebuf+3) |= LDNS_Z_MASK) #define LDNS_Z_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_Z_MASK) #define LDNS_RA_MASK 0x80U #define LDNS_RA_SHIFT 7 #define LDNS_RA_WIRE(wirebuf) (*(wirebuf+3) & LDNS_RA_MASK) #define LDNS_RA_SET(wirebuf) (*(wirebuf+3) |= LDNS_RA_MASK) #define LDNS_RA_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_RA_MASK) /* Query ID */ #define LDNS_ID_WIRE(wirebuf) (ldns_read_uint16(wirebuf)) #define LDNS_ID_SET(wirebuf, id) (ldns_write_uint16(wirebuf, id)) /* Counter of the question section */ #define LDNS_QDCOUNT_OFF 4 /* #define QDCOUNT(wirebuf) (ntohs(*(uint16_t *)(wirebuf+QDCOUNT_OFF))) */ #define LDNS_QDCOUNT(wirebuf) (ldns_read_uint16(wirebuf+LDNS_QDCOUNT_OFF)) /* Counter of the answer section */ #define LDNS_ANCOUNT_OFF 6 #define LDNS_ANCOUNT(wirebuf) (ldns_read_uint16(wirebuf+LDNS_ANCOUNT_OFF)) /* Counter of the authority section */ #define LDNS_NSCOUNT_OFF 8 #define LDNS_NSCOUNT(wirebuf) (ldns_read_uint16(wirebuf+LDNS_NSCOUNT_OFF)) /* Counter of the additional section */ #define LDNS_ARCOUNT_OFF 10 #define LDNS_ARCOUNT(wirebuf) (ldns_read_uint16(wirebuf+LDNS_ARCOUNT_OFF)) /** * converts the data on the uint8_t bytearray (in wire format) to a DNS packet. * This function will initialize and allocate memory space for the packet * structure. * * \param[in] packet pointer to the structure to hold the packet * \param[in] data pointer to the buffer with the data * \param[in] len the length of the data buffer (in bytes) * \return LDNS_STATUS_OK if everything succeeds, error otherwise */ ldns_status ldns_wire2pkt(ldns_pkt **packet, const uint8_t *data, size_t len); /** * converts the data on the uint8_t bytearray (in wire format) to a DNS packet. * This function will initialize and allocate memory space for the packet * structure. * * \param[in] packet pointer to the structure to hold the packet * \param[in] buffer the buffer with the data * \return LDNS_STATUS_OK if everything succeeds, error otherwise */ ldns_status ldns_buffer2pkt_wire(ldns_pkt **packet, ldns_buffer *buffer); /** * converts the data on the uint8_t bytearray (in wire format) to a DNS * dname rdata field. This function will initialize and allocate memory * space for the dname structure. The length of the wiredata of this rdf * is added to the *pos value. * * \param[in] dname pointer to the structure to hold the rdata value * \param[in] wire pointer to the buffer with the data * \param[in] max the length of the data buffer (in bytes) * \param[in] pos the position of the rdf in the buffer (ie. the number of bytes * from the start of the buffer) * \return LDNS_STATUS_OK if everything succeeds, error otherwise */ ldns_status ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos); /** * converts the data on the uint8_t bytearray (in wire format) to DNS * rdata fields, and adds them to the list of rdfs of the given rr. * This function will initialize and allocate memory space for the dname * structures. * The length of the wiredata of these rdfs is added to the *pos value. * * All rdfs belonging to the RR are read; the rr should have no rdfs * yet. An error is returned if the format cannot be parsed. * * \param[in] rr pointer to the ldns_rr structure to hold the rdata value * \param[in] wire pointer to the buffer with the data * \param[in] max the length of the data buffer (in bytes) * \param[in] pos the position of the rdf in the buffer (ie. the number of bytes * from the start of the buffer) * \return LDNS_STATUS_OK if everything succeeds, error otherwise */ ldns_status ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos); /** * converts the data on the uint8_t bytearray (in wire format) to a DNS * resource record. * This function will initialize and allocate memory space for the rr * structure. * The length of the wiredata of this rr is added to the *pos value. * * \param[in] rr pointer to the structure to hold the rdata value * \param[in] wire pointer to the buffer with the data * \param[in] max the length of the data buffer (in bytes) * \param[in] pos the position of the rr in the buffer (ie. the number of bytes * from the start of the buffer) * \param[in] section the section in the packet the rr is meant for * \return LDNS_STATUS_OK if everything succeeds, error otherwise */ ldns_status ldns_wire2rr(ldns_rr **rr, const uint8_t *wire, size_t max, size_t *pos, ldns_pkt_section section); #ifdef __cplusplus } #endif #endif /* LDNS_WIRE2HOST_H */ Net-LDNS-0.75/include/ldns/zone.h000644 000770 000024 00000011045 12471046240 017024 0ustar00calledstaff000000 000000 /** * zone.h * * zone definitions * - what is it * - get_glue function * - search etc * * a Net::DNS like library for C * * (c) NLnet Labs, 2005-2006 * * See the file LICENSE for the license */ /** * \file * * Defines the ldns_zone structure and functions to manipulate it. */ #ifndef LDNS_ZONE_H #define LDNS_ZONE_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * DNS Zone * * A list of RR's with some * extra information which comes from the SOA RR * Note: nothing has been done to make this efficient (yet). */ struct ldns_struct_zone { /** the soa defines a zone */ ldns_rr *_soa; /* basicly a zone is a list of rr's */ ldns_rr_list *_rrs; /* we could change this to be a b-tree etc etc todo */ }; typedef struct ldns_struct_zone ldns_zone; /** * create a new ldns_zone structure * \return a pointer to a ldns_zone structure */ ldns_zone * ldns_zone_new(void); /** * Return the soa record of a zone * \param[in] z the zone to read from * \return the soa record in the zone */ ldns_rr * ldns_zone_soa(const ldns_zone *z); /** * Returns the number of resource records in the zone, NOT counting the SOA record * \param[in] z the zone to read from * \return the number of rr's in the zone */ size_t ldns_zone_rr_count(const ldns_zone *z); /** * Set the zone's soa record * \param[in] z the zone to put the new soa in * \param[in] soa the soa to set */ void ldns_zone_set_soa(ldns_zone *z, ldns_rr *soa); /** * Get a list of a zone's content. Note that the SOA * isn't included in this list. You need to get the * with ldns_zone_soa. * \param[in] z the zone to read from * \return the rrs from this zone */ ldns_rr_list * ldns_zone_rrs(const ldns_zone *z); /** * Set the zone's contents * \param[in] z the zone to put the new soa in * \param[in] rrlist the rrlist to use */ void ldns_zone_set_rrs(ldns_zone *z, ldns_rr_list *rrlist); /** * push an rrlist to a zone structure. This function use pointer * copying, so the rr_list structure inside z is modified! * \param[in] z the zone to add to * \param[in] list the list to add * \return a true on succes otherwise falsed */ bool ldns_zone_push_rr_list(ldns_zone *z, ldns_rr_list *list); /** * push an single rr to a zone structure. This function use pointer * copying, so the rr_list structure inside z is modified! * \param[in] z the zone to add to * \param[in] rr the rr to add * \return a true on succes otherwise falsed */ bool ldns_zone_push_rr(ldns_zone *z, ldns_rr *rr); /** * Retrieve all resource records from the zone that are glue * records. The resulting list does are pointer references * to the zone's data. * * Due to the current zone implementation (as a list of rr's), this * function is extremely slow. Another (probably better) way to do this * is to use an ldns_dnssec_zone structure and the * ldns_dnssec_mark_and_get_glue() function. * * \param[in] z the zone to look for glue * \return the rr_list with the glue */ ldns_rr_list *ldns_zone_glue_rr_list(const ldns_zone *z); /** * Create a new zone from a file * \param[out] z the new zone * \param[in] *fp the filepointer to use * \param[in] *origin the zones' origin * \param[in] ttl default ttl to use * \param[in] c default class to use (IN) * * \return ldns_status mesg with an error or LDNS_STATUS_OK */ ldns_status ldns_zone_new_frm_fp(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, ldns_rr_class c); /** * Create a new zone from a file, keep track of the line numbering * \param[out] z the new zone * \param[in] *fp the filepointer to use * \param[in] *origin the zones' origin * \param[in] ttl default ttl to use * \param[in] c default class to use (IN) * \param[out] line_nr used for error msg, to get to the line number * * \return ldns_status mesg with an error or LDNS_STATUS_OK */ ldns_status ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, ldns_rr_class c, int *line_nr); /** * Frees the allocated memory for the zone, and the rr_list structure in it * \param[in] zone the zone to free */ void ldns_zone_free(ldns_zone *zone); /** * Frees the allocated memory for the zone, the soa rr in it, * and the rr_list structure in it, including the rr's in that. etc. * \param[in] zone the zone to free */ void ldns_zone_deep_free(ldns_zone *zone); /** * Sort the rrs in a zone, with the current impl. this is slow * \param[in] zone the zone to sort */ void ldns_zone_sort(ldns_zone *zone); #ifdef __cplusplus } #endif #endif /* LDNS_ZONE_H */ Net-LDNS-0.75/inc/Module/000755 000770 000024 00000000000 12510741546 015317 5ustar00calledstaff000000 000000 Net-LDNS-0.75/inc/Module/Install/000755 000770 000024 00000000000 12510741546 016725 5ustar00calledstaff000000 000000 Net-LDNS-0.75/inc/Module/Install.pm000644 000770 000024 00000030217 12510720176 017262 0ustar00calledstaff000000 000000 #line 1 package Module::Install; # For any maintainers: # The load order for Module::Install is a bit magic. # It goes something like this... # # IF ( host has Module::Install installed, creating author mode ) { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install # 3. The installed version of inc::Module::Install loads # 4. inc::Module::Install calls "require Module::Install" # 5. The ./inc/ version of Module::Install loads # } ELSE { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install # 3. The ./inc/ version of Module::Install loads # } use 5.006; use strict 'vars'; use Cwd (); use File::Find (); use File::Path (); use vars qw{$VERSION $MAIN}; BEGIN { # All Module::Install core packages now require synchronised versions. # This will be used to ensure we don't accidentally load old or # different versions of modules. # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. $VERSION = '1.14'; # Storage for the pseudo-singleton $MAIN = undef; *inc::Module::Install::VERSION = *VERSION; @inc::Module::Install::ISA = __PACKAGE__; } sub import { my $class = shift; my $self = $class->new(@_); my $who = $self->_caller; #------------------------------------------------------------- # all of the following checks should be included in import(), # to allow "eval 'require Module::Install; 1' to test # installation of Module::Install. (RT #51267) #------------------------------------------------------------- # Whether or not inc::Module::Install is actually loaded, the # $INC{inc/Module/Install.pm} is what will still get set as long as # the caller loaded module this in the documented manner. # If not set, the caller may NOT have loaded the bundled version, and thus # they may not have a MI version that works with the Makefile.PL. This would # result in false errors or unexpected behaviour. And we don't want that. my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: use inc::${\__PACKAGE__}; not: use ${\__PACKAGE__}; END_DIE # This reportedly fixes a rare Win32 UTC file time issue, but # as this is a non-cross-platform XS module not in the core, # we shouldn't really depend on it. See RT #24194 for detail. # (Also, this module only supports Perl 5.6 and above). eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; # If the script that is loading Module::Install is from the future, # then make will detect this and cause it to re-run over and over # again. This is bad. Rather than taking action to touch it (which # is unreliable on some platforms and requires write permissions) # for now we should catch this and refuse to run. if ( -f $0 ) { my $s = (stat($0))[9]; # If the modification time is only slightly in the future, # sleep briefly to remove the problem. my $a = $s - time; if ( $a > 0 and $a < 5 ) { sleep 5 } # Too far in the future, throw an error. my $t = time; if ( $s > $t ) { die <<"END_DIE" } Your installer $0 has a modification time in the future ($s > $t). This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE } # Build.PL was formerly supported, but no longer is due to excessive # difficulty in implementing every single feature twice. if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. It was impossible to maintain duel backends, and has been deprecated. Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE #------------------------------------------------------------- # To save some more typing in Module::Install installers, every... # use inc::Module::Install # ...also acts as an implicit use strict. $^H |= strict::bits(qw(refs subs vars)); #------------------------------------------------------------- unless ( -f $self->{file} ) { foreach my $key (keys %INC) { delete $INC{$key} if $key =~ /Module\/Install/; } local $^W; require "$self->{path}/$self->{dispatch}.pm"; File::Path::mkpath("$self->{prefix}/$self->{author}"); $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); $self->{admin}->init; @_ = ($class, _self => $self); goto &{"$self->{name}::import"}; } local $^W; *{"${who}::AUTOLOAD"} = $self->autoload; $self->preload; # Unregister loader and worker packages so subdirs can use them again delete $INC{'inc/Module/Install.pm'}; delete $INC{'Module/Install.pm'}; # Save to the singleton $MAIN = $self; return 1; } sub autoload { my $self = shift; my $who = $self->_caller; my $cwd = Cwd::getcwd(); my $sym = "${who}::AUTOLOAD"; $sym->{$cwd} = sub { my $pwd = Cwd::getcwd(); if ( my $code = $sym->{$pwd} ) { # Delegate back to parent dirs goto &$code unless $cwd eq $pwd; } unless ($$sym =~ s/([^:]+)$//) { # XXX: it looks like we can't retrieve the missing function # via $$sym (usually $main::AUTOLOAD) in this case. # I'm still wondering if we should slurp Makefile.PL to # get some context or not ... my ($package, $file, $line) = caller; die <<"EOT"; Unknown function is found at $file line $line. Execution of $file aborted due to runtime errors. If you're a contributor to a project, you may need to install some Module::Install extensions from CPAN (or other repository). If you're a user of a module, please contact the author. EOT } my $method = $1; if ( uc($method) eq $method ) { # Do nothing return; } elsif ( $method =~ /^_/ and $self->can($method) ) { # Dispatch to the root M:I class return $self->$method(@_); } # Dispatch to the appropriate plugin unshift @_, ( $self, $1 ); goto &{$self->can('call')}; }; } sub preload { my $self = shift; unless ( $self->{extensions} ) { $self->load_extensions( "$self->{prefix}/$self->{path}", $self ); } my @exts = @{$self->{extensions}}; unless ( @exts ) { @exts = $self->{admin}->load_all_extensions; } my %seen; foreach my $obj ( @exts ) { while (my ($method, $glob) = each %{ref($obj) . '::'}) { next unless $obj->can($method); next if $method =~ /^_/; next if $method eq uc($method); $seen{$method}++; } } my $who = $self->_caller; foreach my $name ( sort keys %seen ) { local $^W; *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; }; } } sub new { my ($class, %args) = @_; delete $INC{'FindBin.pm'}; { # to suppress the redefine warning local $SIG{__WARN__} = sub {}; require FindBin; } # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::getcwd()) eq $base_path ) { delete $args{prefix}; } return $args{_self} if $args{_self}; $args{dispatch} ||= 'Admin'; $args{prefix} ||= 'inc'; $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); $args{bundle} ||= 'inc/BUNDLES'; $args{base} ||= $base_path; $class =~ s/^\Q$args{prefix}\E:://; $args{name} ||= $class; $args{version} ||= $class->VERSION; unless ( $args{path} ) { $args{path} = $args{name}; $args{path} =~ s!::!/!g; } $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; $args{wrote} = 0; bless( \%args, $class ); } sub call { my ($self, $method) = @_; my $obj = $self->load($method) or return; splice(@_, 0, 2, $obj); goto &{$obj->can($method)}; } sub load { my ($self, $method) = @_; $self->load_extensions( "$self->{prefix}/$self->{path}", $self ) unless $self->{extensions}; foreach my $obj (@{$self->{extensions}}) { return $obj if $obj->can($method); } my $admin = $self->{admin} or die <<"END_DIE"; The '$method' method does not exist in the '$self->{prefix}' path! Please remove the '$self->{prefix}' directory and run $0 again to load it. END_DIE my $obj = $admin->load($method, 1); push @{$self->{extensions}}, $obj; $obj; } sub load_extensions { my ($self, $path, $top) = @_; my $should_reload = 0; unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; $should_reload = 1; } foreach my $rv ( $self->find_extensions($path) ) { my ($file, $pkg) = @{$rv}; next if $self->{pathnames}{$pkg}; local $@; my $new = eval { local $^W; require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } $self->{pathnames}{$pkg} = $should_reload ? delete $INC{$file} : $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } $self->{extensions} ||= []; } sub find_extensions { my ($self, $path) = @_; my @found; File::Find::find( sub { my $file = $File::Find::name; return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; my $subpath = $1; return if lc($subpath) eq lc($self->{dispatch}); $file = "$self->{path}/$subpath.pm"; my $pkg = "$self->{name}::$subpath"; $pkg =~ s!/!::!g; # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { my $content = Module::Install::_read($subpath . '.pm'); my $in_pod = 0; foreach ( split /\n/, $content ) { $in_pod = 1 if /^=\w/; $in_pod = 0 if /^=cut/; next if ($in_pod || /^=cut/); # skip pod text next if /^\s*#/; # and comments if ( m/^\s*package\s+($pkg)\s*;/i ) { $pkg = $1; last; } } } push @found, [ $file, $pkg ]; }, $path ) if -d $path; @found; } ##################################################################### # Common Utility Functions sub _caller { my $depth = 0; my $call = caller($depth); while ( $call eq __PACKAGE__ ) { $depth++; $call = caller($depth); } return $call; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _read { local *FH; open( FH, '<', $_[0] ) or die "open($_[0]): $!"; binmode FH; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_NEW sub _read { local *FH; open( FH, "< $_[0]" ) or die "open($_[0]): $!"; binmode FH; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_OLD sub _readperl { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; $string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s; $string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg; return $string; } sub _readpod { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; return $string if $_[0] =~ /\.pod\z/; $string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg; $string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg; $string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg; $string =~ s/^\n+//s; return $string; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _write { local *FH; open( FH, '>', $_[0] ) or die "open($_[0]): $!"; binmode FH; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_NEW sub _write { local *FH; open( FH, "> $_[0]" ) or die "open($_[0]): $!"; binmode FH; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_OLD # _version is for processing module versions (eg, 1.03_05) not # Perl versions (eg, 5.8.1). sub _version { my $s = shift || 0; my $d =()= $s =~ /(\.)/g; if ( $d >= 2 ) { # Normalise multipart versions $s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg; } $s =~ s/^(\d+)\.?//; my $l = $1 || 0; my @v = map { $_ . '0' x (3 - length $_) } $s =~ /(\d{1,3})\D?/g; $l = $l . '.' . join '', @v if @v; return $l + 0; } sub _cmp { _version($_[1]) <=> _version($_[2]); } # Cloned from Params::Util::_CLASS sub _CLASS { ( defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s ) ? $_[0] : undef; } 1; # Copyright 2008 - 2012 Adam Kennedy. Net-LDNS-0.75/inc/Module/Install/Base.pm000644 000770 000024 00000002147 12510720176 020135 0ustar00calledstaff000000 000000 #line 1 package Module::Install::Base; use strict 'vars'; use vars qw{$VERSION}; BEGIN { $VERSION = '1.14'; } # Suspend handler for "redefined" warnings BEGIN { my $w = $SIG{__WARN__}; $SIG{__WARN__} = sub { $w }; } #line 42 sub new { my $class = shift; unless ( defined &{"${class}::call"} ) { *{"${class}::call"} = sub { shift->_top->call(@_) }; } unless ( defined &{"${class}::load"} ) { *{"${class}::load"} = sub { shift->_top->load(@_) }; } bless { @_ }, $class; } #line 61 sub AUTOLOAD { local $@; my $func = eval { shift->_top->autoload } or return; goto &$func; } #line 75 sub _top { $_[0]->{_top}; } #line 90 sub admin { $_[0]->_top->{admin} or Module::Install::Base::FakeAdmin->new; } #line 106 sub is_admin { ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); } sub DESTROY {} package Module::Install::Base::FakeAdmin; use vars qw{$VERSION}; BEGIN { $VERSION = $Module::Install::Base::VERSION; } my $fake; sub new { $fake ||= bless(\@_, $_[0]); } sub AUTOLOAD {} sub DESTROY {} # Restore warning handler BEGIN { $SIG{__WARN__} = $SIG{__WARN__}->(); } 1; #line 159 Net-LDNS-0.75/inc/Module/Install/Can.pm000644 000770 000024 00000006157 12510720176 017771 0ustar00calledstaff000000 000000 #line 1 package Module::Install::Can; use strict; use Config (); use ExtUtils::MakeMaker (); use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # check if we can load some module ### Upgrade this to not have to load the module if possible sub can_use { my ($self, $mod, $ver) = @_; $mod =~ s{::|\\}{/}g; $mod .= '.pm' unless $mod =~ /\.pm$/i; my $pkg = $mod; $pkg =~ s{/}{::}g; $pkg =~ s{\.pm$}{}i; local $@; eval { require $mod; $pkg->VERSION($ver || 0); 1 }; } # Check if we can run some command sub can_run { my ($self, $cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { next if $dir eq ''; require File::Spec; my $abs = File::Spec->catfile($dir, $cmd); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # Can our C compiler environment build XS files sub can_xs { my $self = shift; # Ensure we have the CBuilder module $self->configure_requires( 'ExtUtils::CBuilder' => 0.27 ); # Do we have the configure_requires checker? local $@; eval "require ExtUtils::CBuilder;"; if ( $@ ) { # They don't obey configure_requires, so it is # someone old and delicate. Try to avoid hurting # them by falling back to an older simpler test. return $self->can_cc(); } # Do we have a working C compiler my $builder = ExtUtils::CBuilder->new( quiet => 1, ); unless ( $builder->have_compiler ) { # No working C compiler return 0; } # Write a C file representative of what XS becomes require File::Temp; my ( $FH, $tmpfile ) = File::Temp::tempfile( "compilexs-XXXXX", SUFFIX => '.c', ); binmode $FH; print $FH <<'END_C'; #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int main(int argc, char **argv) { return 0; } int boot_sanexs() { return 1; } END_C close $FH; # Can the C compiler access the same headers XS does my @libs = (); my $object = undef; eval { local $^W = 0; $object = $builder->compile( source => $tmpfile, ); @libs = $builder->link( objects => $object, module_name => 'sanexs', ); }; my $result = $@ ? 0 : 1; # Clean up all the build files foreach ( $tmpfile, $object, @libs ) { next unless defined $_; 1 while unlink; } return $result; } # Can we locate a (the) C compiler sub can_cc { my $self = shift; my @chunks = split(/ /, $Config::Config{cc}) or return; # $Config{cc} may contain args; try to find out the program part while (@chunks) { return $self->can_run("@chunks") || (pop(@chunks), next); } return; } # Fix Cygwin bug on maybe_command(); if ( $^O eq 'cygwin' ) { require ExtUtils::MM_Cygwin; require ExtUtils::MM_Win32; if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { *ExtUtils::MM_Cygwin::maybe_command = sub { my ($self, $file) = @_; if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { ExtUtils::MM_Win32->maybe_command($file); } else { ExtUtils::MM_Unix->maybe_command($file); } } } } 1; __END__ #line 236 Net-LDNS-0.75/inc/Module/Install/Fetch.pm000644 000770 000024 00000004627 12510720200 020305 0ustar00calledstaff000000 000000 #line 1 package Module::Install::Fetch; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub get_file { my ($self, %args) = @_; my ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { $args{url} = $args{ftp_url} or (warn("LWP support unavailable!\n"), return); ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; } $|++; print "Fetching '$file' from $host... "; unless (eval { require Socket; Socket::inet_aton($host) }) { warn "'$host' resolve failed!\n"; return; } return unless $scheme eq 'ftp' or $scheme eq 'http'; require Cwd; my $dir = Cwd::getcwd(); chdir $args{local_dir} or return if exists $args{local_dir}; if (eval { require LWP::Simple; 1 }) { LWP::Simple::mirror($args{url}, $file); } elsif (eval { require Net::FTP; 1 }) { eval { # use Net::FTP to get past firewall my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); $ftp->login("anonymous", 'anonymous@example.com'); $ftp->cwd($path); $ftp->binary; $ftp->get($file) or (warn("$!\n"), return); $ftp->quit; } } elsif (my $ftp = $self->can_run('ftp')) { eval { # no Net::FTP, fallback to ftp.exe require FileHandle; my $fh = FileHandle->new; local $SIG{CHLD} = 'IGNORE'; unless ($fh->open("|$ftp -n")) { warn "Couldn't open ftp: $!\n"; chdir $dir; return; } my @dialog = split(/\n/, <<"END_FTP"); open $host user anonymous anonymous\@example.com cd $path binary get $file $file quit END_FTP foreach (@dialog) { $fh->print("$_\n") } $fh->close; } } else { warn "No working 'ftp' program available!\n"; chdir $dir; return; } unless (-f $file) { warn "Fetching failed: $@\n"; chdir $dir; return; } return if exists $args{size} and -s $file != $args{size}; system($args{run}) if exists $args{run}; unlink($file) if $args{remove}; print(((!exists $args{check_for} or -e $args{check_for}) ? "done!" : "failed! ($!)"), "\n"); chdir $dir; return !$?; } 1; Net-LDNS-0.75/inc/Module/Install/Makefile.pm000644 000770 000024 00000027437 12510720176 021011 0ustar00calledstaff000000 000000 #line 1 package Module::Install::Makefile; use strict 'vars'; use ExtUtils::MakeMaker (); use Module::Install::Base (); use Fcntl qw/:flock :seek/; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub Makefile { $_[0] } my %seen = (); sub prompt { shift; # Infinite loop protection my @c = caller(); if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } # In automated testing or non-interactive session, always use defaults if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { goto &ExtUtils::MakeMaker::prompt; } } # Store a cleaned up version of the MakeMaker version, # since we need to behave differently in a variety of # ways based on the MM version. my $makemaker = eval $ExtUtils::MakeMaker::VERSION; # If we are passed a param, do a "newer than" comparison. # Otherwise, just return the MakeMaker version. sub makemaker { ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 } # Ripped from ExtUtils::MakeMaker 6.56, and slightly modified # as we only need to know here whether the attribute is an array # or a hash or something else (which may or may not be appendable). my %makemaker_argtype = ( C => 'ARRAY', CONFIG => 'ARRAY', # CONFIGURE => 'CODE', # ignore DIR => 'ARRAY', DL_FUNCS => 'HASH', DL_VARS => 'ARRAY', EXCLUDE_EXT => 'ARRAY', EXE_FILES => 'ARRAY', FUNCLIST => 'ARRAY', H => 'ARRAY', IMPORTS => 'HASH', INCLUDE_EXT => 'ARRAY', LIBS => 'ARRAY', # ignore '' MAN1PODS => 'HASH', MAN3PODS => 'HASH', META_ADD => 'HASH', META_MERGE => 'HASH', PL_FILES => 'HASH', PM => 'HASH', PMLIBDIRS => 'ARRAY', PMLIBPARENTDIRS => 'ARRAY', PREREQ_PM => 'HASH', CONFIGURE_REQUIRES => 'HASH', SKIP => 'ARRAY', TYPEMAPS => 'ARRAY', XS => 'HASH', # VERSION => ['version',''], # ignore # _KEEP_AFTER_FLUSH => '', clean => 'HASH', depend => 'HASH', dist => 'HASH', dynamic_lib=> 'HASH', linkext => 'HASH', macro => 'HASH', postamble => 'HASH', realclean => 'HASH', test => 'HASH', tool_autosplit => 'HASH', # special cases where you can use makemaker_append CCFLAGS => 'APPENDABLE', DEFINE => 'APPENDABLE', INC => 'APPENDABLE', LDDLFLAGS => 'APPENDABLE', LDFROM => 'APPENDABLE', ); sub makemaker_args { my ($self, %new_args) = @_; my $args = ( $self->{makemaker_args} ||= {} ); foreach my $key (keys %new_args) { if ($makemaker_argtype{$key}) { if ($makemaker_argtype{$key} eq 'ARRAY') { $args->{$key} = [] unless defined $args->{$key}; unless (ref $args->{$key} eq 'ARRAY') { $args->{$key} = [$args->{$key}] } push @{$args->{$key}}, ref $new_args{$key} eq 'ARRAY' ? @{$new_args{$key}} : $new_args{$key}; } elsif ($makemaker_argtype{$key} eq 'HASH') { $args->{$key} = {} unless defined $args->{$key}; foreach my $skey (keys %{ $new_args{$key} }) { $args->{$key}{$skey} = $new_args{$key}{$skey}; } } elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { $self->makemaker_append($key => $new_args{$key}); } } else { if (defined $args->{$key}) { warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; } $args->{$key} = $new_args{$key}; } } return $args; } # For mm args that take multiple space-separated args, # append an argument to the current list. sub makemaker_append { my $self = shift; my $name = shift; my $args = $self->makemaker_args; $args->{$name} = defined $args->{$name} ? join( ' ', $args->{$name}, @_ ) : join( ' ', @_ ); } sub build_subdirs { my $self = shift; my $subdirs = $self->makemaker_args->{DIR} ||= []; for my $subdir (@_) { push @$subdirs, $subdir; } } sub clean_files { my $self = shift; my $clean = $self->makemaker_args->{clean} ||= {}; %$clean = ( %$clean, FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), ); } sub realclean_files { my $self = shift; my $realclean = $self->makemaker_args->{realclean} ||= {}; %$realclean = ( %$realclean, FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), ); } sub libs { my $self = shift; my $libs = ref $_[0] ? shift : [ shift ]; $self->makemaker_args( LIBS => $libs ); } sub inc { my $self = shift; $self->makemaker_args( INC => shift ); } sub _wanted_t { } sub tests_recursive { my $self = shift; my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } my %tests = map { $_ => 1 } split / /, ($self->tests || ''); require File::Find; File::Find::find( sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, $dir ); $self->tests( join ' ', sort keys %tests ); } sub write { my $self = shift; die "&Makefile->write() takes no arguments\n" if @_; # Check the current Perl version my $perl_version = $self->perl_version; if ( $perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; } # Make sure we have a new enough MakeMaker require ExtUtils::MakeMaker; if ( $perl_version and $self->_cmp($perl_version, '5.006') >= 0 ) { # This previous attempted to inherit the version of # ExtUtils::MakeMaker in use by the module author, but this # was found to be untenable as some authors build releases # using future dev versions of EU:MM that nobody else has. # Instead, #toolchain suggests we use 6.59 which is the most # stable version on CPAN at time of writing and is, to quote # ribasushi, "not terminally fucked, > and tested enough". # TODO: We will now need to maintain this over time to push # the version up as new versions are released. $self->build_requires( 'ExtUtils::MakeMaker' => 6.59 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.59 ); } else { # Allow legacy-compatibility with 5.005 by depending on the # most recent EU:MM that supported 5.005. $self->build_requires( 'ExtUtils::MakeMaker' => 6.36 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.36 ); } # Generate the MakeMaker params my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; $args->{NAME} =~ s/-/::/g; $args->{VERSION} = $self->version or die <<'EOT'; ERROR: Can't determine distribution version. Please specify it explicitly via 'version' in Makefile.PL, or set a valid $VERSION in a module, and provide its file path via 'version_from' (or 'all_from' if you prefer) in Makefile.PL. EOT if ( $self->tests ) { my @tests = split ' ', $self->tests; my %seen; $args->{test} = { TESTS => (join ' ', grep {!$seen{$_}++} @tests), }; } elsif ( $Module::Install::ExtraTests::use_extratests ) { # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. # So, just ignore our xt tests here. } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { $args->{test} = { TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), }; } if ( $] >= 5.005 ) { $args->{ABSTRACT} = $self->abstract; $args->{AUTHOR} = join ', ', @{$self->author || []}; } if ( $self->makemaker(6.10) ) { $args->{NO_META} = 1; #$args->{NO_MYMETA} = 1; } if ( $self->makemaker(6.17) and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } if ( $self->makemaker(6.31) and $self->license ) { $args->{LICENSE} = $self->license; } my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; # Merge both kinds of requires into BUILD_REQUIRES my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); %$build_prereq = ( %$build_prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->configure_requires, $self->build_requires) ); # Remove any reference to perl, BUILD_REQUIRES doesn't support it delete $args->{BUILD_REQUIRES}->{perl}; # Delete bundled dists from prereq_pm, add it to Makefile DIR my $subdirs = ($args->{DIR} || []); if ($self->bundles) { my %processed; foreach my $bundle (@{ $self->bundles }) { my ($mod_name, $dist_dir) = @$bundle; delete $prereq->{$mod_name}; $dist_dir = File::Basename::basename($dist_dir); # dir for building this module if (not exists $processed{$dist_dir}) { if (-d $dist_dir) { # List as sub-directory to be processed by make push @$subdirs, $dist_dir; } # Else do nothing: the module is already present on the system $processed{$dist_dir} = undef; } } } unless ( $self->makemaker('6.55_03') ) { %$prereq = (%$prereq,%$build_prereq); delete $args->{BUILD_REQUIRES}; } if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; if ( $self->makemaker(6.48) ) { $args->{MIN_PERL_VERSION} = $perl_version; } } if ($self->installdirs) { warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; $args->{INSTALLDIRS} = $self->installdirs; } my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) } keys %$args; my $user_preop = delete $args{dist}->{PREOP}; if ( my $preop = $self->admin->preop($user_preop) ) { foreach my $key ( keys %$preop ) { $args{dist}->{$key} = $preop->{$key}; } } my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); } sub fix_up_makefile { my $self = shift; my $makefile_name = shift; my $top_class = ref($self->_top) || ''; my $top_version = $self->_top->VERSION || ''; my $preamble = $self->preamble ? "# Preamble by $top_class $top_version\n" . $self->preamble : ''; my $postamble = "# Postamble by $top_class $top_version\n" . ($self->postamble || ''); local *MAKEFILE; open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; eval { flock MAKEFILE, LOCK_EX }; my $makefile = do { local $/; }; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; # Module::Install will never be used to build the Core Perl # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; seek MAKEFILE, 0, SEEK_SET; truncate MAKEFILE, 0; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; 1; } sub preamble { my ($self, $text) = @_; $self->{preamble} = $text . $self->{preamble} if defined $text; $self->{preamble}; } sub postamble { my ($self, $text) = @_; $self->{postamble} ||= $self->admin->postamble; $self->{postamble} .= $text if defined $text; $self->{postamble} } 1; __END__ #line 544 Net-LDNS-0.75/inc/Module/Install/Metadata.pm000644 000770 000024 00000043302 12510720176 021001 0ustar00calledstaff000000 000000 #line 1 package Module::Install::Metadata; use strict 'vars'; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } my @boolean_keys = qw{ sign }; my @scalar_keys = qw{ name module_name abstract version distribution_type tests installdirs }; my @tuple_keys = qw{ configure_requires build_requires requires recommends bundles resources }; my @resource_keys = qw{ homepage bugtracker repository }; my @array_keys = qw{ keywords author }; *authors = \&author; sub Meta { shift } sub Meta_BooleanKeys { @boolean_keys } sub Meta_ScalarKeys { @scalar_keys } sub Meta_TupleKeys { @tuple_keys } sub Meta_ResourceKeys { @resource_keys } sub Meta_ArrayKeys { @array_keys } foreach my $key ( @boolean_keys ) { *$key = sub { my $self = shift; if ( defined wantarray and not @_ ) { return $self->{values}->{$key}; } $self->{values}->{$key} = ( @_ ? $_[0] : 1 ); return $self; }; } foreach my $key ( @scalar_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} = shift; return $self; }; } foreach my $key ( @array_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} ||= []; push @{$self->{values}->{$key}}, @_; return $self; }; } foreach my $key ( @resource_keys ) { *$key = sub { my $self = shift; unless ( @_ ) { return () unless $self->{values}->{resources}; return map { $_->[1] } grep { $_->[0] eq $key } @{ $self->{values}->{resources} }; } return $self->{values}->{resources}->{$key} unless @_; my $uri = shift or die( "Did not provide a value to $key()" ); $self->resources( $key => $uri ); return 1; }; } foreach my $key ( grep { $_ ne "resources" } @tuple_keys) { *$key = sub { my $self = shift; return $self->{values}->{$key} unless @_; my @added; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @added, [ $module, $version ]; } push @{ $self->{values}->{$key} }, @added; return map {@$_} @added; }; } # Resource handling my %lc_resource = map { $_ => 1 } qw{ homepage license bugtracker repository }; sub resources { my $self = shift; while ( @_ ) { my $name = shift or last; my $value = shift or next; if ( $name eq lc $name and ! $lc_resource{$name} ) { die("Unsupported reserved lowercase resource '$name'"); } $self->{values}->{resources} ||= []; push @{ $self->{values}->{resources} }, [ $name, $value ]; } $self->{values}->{resources}; } # Aliases for build_requires that will have alternative # meanings in some future version of META.yml. sub test_requires { shift->build_requires(@_) } sub install_requires { shift->build_requires(@_) } # Aliases for installdirs options sub install_as_core { $_[0]->installdirs('perl') } sub install_as_cpan { $_[0]->installdirs('site') } sub install_as_site { $_[0]->installdirs('site') } sub install_as_vendor { $_[0]->installdirs('vendor') } sub dynamic_config { my $self = shift; my $value = @_ ? shift : 1; if ( $self->{values}->{dynamic_config} ) { # Once dynamic we never change to static, for safety return 0; } $self->{values}->{dynamic_config} = $value ? 1 : 0; return 1; } # Convenience command sub static_config { shift->dynamic_config(0); } sub perl_version { my $self = shift; return $self->{values}->{perl_version} unless @_; my $version = shift or die( "Did not provide a value to perl_version()" ); # Normalize the version $version = $self->_perl_version($version); # We don't support the really old versions unless ( $version >= 5.005 ) { die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; } $self->{values}->{perl_version} = $version; } sub all_from { my ( $self, $file ) = @_; unless ( defined($file) ) { my $name = $self->name or die( "all_from called with no args without setting name() first" ); $file = join('/', 'lib', split(/-/, $name)) . '.pm'; $file =~ s{.*/}{} unless -e $file; unless ( -e $file ) { die("all_from cannot find $file from $name"); } } unless ( -f $file ) { die("The path '$file' does not exist, or is not a file"); } $self->{values}{all_from} = $file; # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; $pod =~ s/\.pm$/.pod/i; $pod = $file unless -e $pod; # Pull the different values $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; $self->author_from($pod) unless @{$self->author || []}; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; return 1; } sub provides { my $self = shift; my $provides = ( $self->{values}->{provides} ||= {} ); %$provides = (%$provides, @_) if @_; return $provides; } sub auto_provides { my $self = shift; return $self unless $self->is_admin; unless (-e 'MANIFEST') { warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; return $self; } # Avoid spurious warnings as we are not checking manifest here. local $SIG{__WARN__} = sub {1}; require ExtUtils::Manifest; local *ExtUtils::Manifest::manicheck = sub { return }; require Module::Build; my $build = Module::Build->new( dist_name => $self->name, dist_version => $self->version, license => $self->license, ); $self->provides( %{ $build->find_dist_packages || {} } ); } sub feature { my $self = shift; my $name = shift; my $features = ( $self->{values}->{features} ||= [] ); my $mods; if ( @_ == 1 and ref( $_[0] ) ) { # The user used ->feature like ->features by passing in the second # argument as a reference. Accomodate for that. $mods = $_[0]; } else { $mods = \@_; } my $count = 0; push @$features, ( $name => [ map { ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ } @$mods ] ); return @$features; } sub features { my $self = shift; while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { $self->feature( $name, @$mods ); } return $self->{values}->{features} ? @{ $self->{values}->{features} } : (); } sub no_index { my $self = shift; my $type = shift; push @{ $self->{values}->{no_index}->{$type} }, @_ if $type; return $self->{values}->{no_index}; } sub read { my $self = shift; $self->include_deps( 'YAML::Tiny', 0 ); require YAML::Tiny; my $data = YAML::Tiny::LoadFile('META.yml'); # Call methods explicitly in case user has already set some values. while ( my ( $key, $value ) = each %$data ) { next unless $self->can($key); if ( ref $value eq 'HASH' ) { while ( my ( $module, $version ) = each %$value ) { $self->can($key)->($self, $module => $version ); } } else { $self->can($key)->($self, $value); } } return $self; } sub write { my $self = shift; return $self unless $self->is_admin; $self->admin->write_meta; return $self; } sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); # for version integrity check $self->makemaker_args( VERSION_FROM => $file ); } sub abstract_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->abstract( bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) ); } # Add both distribution and module name sub name_from { my ($self, $file) = @_; if ( Module::Install::_read($file) =~ m/ ^ \s* package \s* ([\w:]+) [\s|;]* /ixms ) { my ($name, $module_name) = ($1, $1); $name =~ s{::}{-}g; $self->name($name); unless ( $self->module_name ) { $self->module_name($module_name); } } else { die("Cannot determine name from $file\n"); } } sub _extract_perl_version { if ( $_[0] =~ m/ ^\s* (?:use|require) \s* v? ([\d_\.]+) \s* ; /ixms ) { my $perl_version = $1; $perl_version =~ s{_}{}g; return $perl_version; } else { return; } } sub perl_version_from { my $self = shift; my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); if ($perl_version) { $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; return; } } sub author_from { my $self = shift; my $content = Module::Install::_read($_[0]); if ($content =~ m/ =head \d \s+ (?:authors?)\b \s* ([^\n]*) | =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* ([^\n]*) /ixms) { my $author = $1 || $2; # XXX: ugly but should work anyway... if (eval "require Pod::Escapes; 1") { # Pod::Escapes has a mapping table. # It's in core of perl >= 5.9.3, and should be installed # as one of the Pod::Simple's prereqs, which is a prereq # of Pod::Text 3.x (see also below). $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $Pod::Escapes::Name2character_number{$1} ? chr($Pod::Escapes::Name2character_number{$1}) : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { # Pod::Text < 3.0 has yet another mapping table, # though the table name of 2.x and 1.x are different. # (1.x is in core of Perl < 5.6, 2.x is in core of # Perl < 5.9.3) my $mapping = ($Pod::Text::VERSION < 2) ? \%Pod::Text::HTML_Escapes : \%Pod::Text::ESCAPES; $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $mapping->{$1} ? $mapping->{$1} : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } else { $author =~ s{E}{<}g; $author =~ s{E}{>}g; } $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } #Stolen from M::B my %license_urls = ( perl => 'http://dev.perl.org/licenses/', apache => 'http://apache.org/licenses/LICENSE-2.0', apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', artistic => 'http://opensource.org/licenses/artistic-license.php', artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', lgpl => 'http://opensource.org/licenses/lgpl-license.php', lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', bsd => 'http://opensource.org/licenses/bsd-license.php', gpl => 'http://opensource.org/licenses/gpl-license.php', gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', mit => 'http://opensource.org/licenses/mit-license.php', mozilla => 'http://opensource.org/licenses/mozilla1.1.php', open_source => undef, unrestricted => undef, restrictive => undef, unknown => undef, ); sub license { my $self = shift; return $self->{values}->{license} unless @_; my $license = shift or die( 'Did not provide a value to license()' ); $license = __extract_license($license) || lc $license; $self->{values}->{license} = $license; # Automatically fill in license URLs if ( $license_urls{$license} ) { $self->resources( license => $license_urls{$license} ); } return 1; } sub _extract_license { my $pod = shift; my $matched; return __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) (=head \d.*|=cut.*|)\z /xms ) || __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) (=head \d.*|=cut.*|)\z /xms ); } sub __extract_license { my $license_text = shift or return; my @phrases = ( '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, 'Artistic and GPL' => 'perl', 1, 'GNU general public license' => 'gpl', 1, 'GNU public license' => 'gpl', 1, 'GNU lesser general public license' => 'lgpl', 1, 'GNU lesser public license' => 'lgpl', 1, 'GNU library general public license' => 'lgpl', 1, 'GNU library public license' => 'lgpl', 1, 'GNU Free Documentation license' => 'unrestricted', 1, 'GNU Affero General Public License' => 'open_source', 1, '(?:Free)?BSD license' => 'bsd', 1, 'Artistic license 2\.0' => 'artistic_2', 1, 'Artistic license' => 'artistic', 1, 'Apache (?:Software )?license' => 'apache', 1, 'GPL' => 'gpl', 1, 'LGPL' => 'lgpl', 1, 'BSD' => 'bsd', 1, 'Artistic' => 'artistic', 1, 'MIT' => 'mit', 1, 'Mozilla Public License' => 'mozilla', 1, 'Q Public License' => 'open_source', 1, 'OpenSSL License' => 'unrestricted', 1, 'SSLeay License' => 'unrestricted', 1, 'zlib License' => 'open_source', 1, 'proprietary' => 'proprietary', 0, ); while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { $pattern =~ s#\s+#\\s+#gs; if ( $license_text =~ /\b$pattern\b/i ) { return $license; } } return ''; } sub license_from { my $self = shift; if (my $license=_extract_license(Module::Install::_read($_[0]))) { $self->license($license); } else { warn "Cannot determine license info from $_[0]\n"; return 'unknown'; } } sub _extract_bugtracker { my @links = $_[0] =~ m#L<( https?\Q://rt.cpan.org/\E[^>]+| https?\Q://github.com/\E[\w_]+/[\w_]+/issues| https?\Q://code.google.com/p/\E[\w_\-]+/issues/list )>#gx; my %links; @links{@links}=(); @links=keys %links; return @links; } sub bugtracker_from { my $self = shift; my $content = Module::Install::_read($_[0]); my @links = _extract_bugtracker($content); unless ( @links ) { warn "Cannot determine bugtracker info from $_[0]\n"; return 0; } if ( @links > 1 ) { warn "Found more than one bugtracker link in $_[0]\n"; return 0; } # Set the bugtracker bugtracker( $links[0] ); return 1; } sub requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+(v?[\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->requires( $module => $version ); } } sub test_requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->test_requires( $module => $version ); } } # Convert triple-part versions (eg, 5.6.1 or 5.8.9) to # numbers (eg, 5.006001 or 5.008009). # Also, convert double-part versions (eg, 5.8) sub _perl_version { my $v = $_[-1]; $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e; $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e; $v =~ s/(\.\d\d\d)000$/$1/; $v =~ s/_.+$//; if ( ref($v) ) { # Numify $v = $v + 0; } return $v; } sub add_metadata { my $self = shift; my %hash = @_; for my $key (keys %hash) { warn "add_metadata: $key is not prefixed with 'x_'.\n" . "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; $self->{values}->{$key} = $hash{$key}; } } ###################################################################### # MYMETA Support sub WriteMyMeta { die "WriteMyMeta has been deprecated"; } sub write_mymeta_yaml { my $self = shift; # We need YAML::Tiny to write the MYMETA.yml file unless ( eval { require YAML::Tiny; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.yml\n"; YAML::Tiny::DumpFile('MYMETA.yml', $meta); } sub write_mymeta_json { my $self = shift; # We need JSON to write the MYMETA.json file unless ( eval { require JSON; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.json\n"; Module::Install::_write( 'MYMETA.json', JSON->new->pretty(1)->canonical->encode($meta), ); } sub _write_mymeta_data { my $self = shift; # If there's no existing META.yml there is nothing we can do return undef unless -f 'META.yml'; # We need Parse::CPAN::Meta to load the file unless ( eval { require Parse::CPAN::Meta; 1; } ) { return undef; } # Merge the perl version into the dependencies my $val = $self->Meta->{values}; my $perl = delete $val->{perl_version}; if ( $perl ) { $val->{requires} ||= []; my $requires = $val->{requires}; # Canonize to three-dot version after Perl 5.6 if ( $perl >= 5.006 ) { $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e } unshift @$requires, [ perl => $perl ]; } # Load the advisory META.yml file my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); my $meta = $yaml[0]; # Overwrite the non-configure dependency hashes delete $meta->{requires}; delete $meta->{build_requires}; delete $meta->{recommends}; if ( exists $val->{requires} ) { $meta->{requires} = { map { @$_ } @{ $val->{requires} } }; } if ( exists $val->{build_requires} ) { $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } }; } return $meta; } 1; Net-LDNS-0.75/inc/Module/Install/Win32.pm000644 000770 000024 00000003403 12510720200 020145 0ustar00calledstaff000000 000000 #line 1 package Module::Install::Win32; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # determine if the user needs nmake, and download it if needed sub check_nmake { my $self = shift; $self->load('can_run'); $self->load('get_file'); require Config; return unless ( $^O eq 'MSWin32' and $Config::Config{make} and $Config::Config{make} =~ /^nmake\b/i and ! $self->can_run('nmake') ); print "The required 'nmake' executable not found, fetching it...\n"; require File::Basename; my $rv = $self->get_file( url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', local_dir => File::Basename::dirname($^X), size => 51928, run => 'Nmake15.exe /o > nul', check_for => 'Nmake.exe', remove => 1, ); die <<'END_MESSAGE' unless $rv; ------------------------------------------------------------------------------- Since you are using Microsoft Windows, you will need the 'nmake' utility before installation. It's available at: http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe or ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe Please download the file manually, save it to a directory in %PATH% (e.g. C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to that directory, and run "Nmake15.exe" from there; that will create the 'nmake.exe' file needed by this module. You may then resume the installation process described in README. ------------------------------------------------------------------------------- END_MESSAGE } 1; Net-LDNS-0.75/inc/Module/Install/WriteAll.pm000644 000770 000024 00000002376 12510720200 020776 0ustar00calledstaff000000 000000 #line 1 package Module::Install::WriteAll; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } sub WriteAll { my $self = shift; my %args = ( meta => 1, sign => 0, inline => 0, check_nmake => 1, @_, ); $self->sign(1) if $args{sign}; $self->admin->WriteAll(%args) if $self->is_admin; $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { # XXX: This still may be a bit over-defensive... unless ($self->makemaker(6.25)) { $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; } } # Until ExtUtils::MakeMaker support MYMETA.yml, make sure # we clean it up properly ourself. $self->realclean_files('MYMETA.yml'); if ( $args{inline} ) { $self->Inline->write; } else { $self->Makefile->write; } # The Makefile write process adds a couple of dependencies, # so write the META.yml files after the Makefile. if ( $args{meta} ) { $self->Meta->write; } # Experimental support for MYMETA if ( $ENV{X_MYMETA} ) { if ( $ENV{X_MYMETA} eq 'JSON' ) { $self->Meta->write_mymeta_json; } else { $self->Meta->write_mymeta_yaml; } } return 1; } 1; Net-LDNS-0.75/inc/Module/Install/XSUtil.pm000644 000770 000024 00000045703 12510720176 020460 0ustar00calledstaff000000 000000 #line 1 package Module::Install::XSUtil; use 5.005_03; $VERSION = '0.45'; use Module::Install::Base; @ISA = qw(Module::Install::Base); use strict; use Config; use File::Spec; use File::Find; use constant _VERBOSE => $ENV{MI_VERBOSE} ? 1 : 0; my %ConfigureRequires = ( 'ExtUtils::ParseXS' => 3.18, # shipped with Perl 5.18.0 ); my %BuildRequires = ( ); my %Requires = ( 'XSLoader' => 0.02, ); my %ToInstall; my $UseC99 = 0; my $UseCplusplus = 0; sub _verbose{ print STDERR q{# }, @_, "\n"; } sub _xs_debugging{ return $ENV{XS_DEBUG} || scalar( grep{ $_ eq '-g' } @ARGV ); } sub _xs_initialize{ my($self) = @_; unless($self->{xsu_initialized}){ $self->{xsu_initialized} = 1; if(!$self->cc_available()){ warn "This distribution requires a C compiler, but it's not available, stopped.\n"; exit; } $self->configure_requires(%ConfigureRequires); $self->build_requires(%BuildRequires); $self->requires(%Requires); $self->makemaker_args->{OBJECT} = '$(O_FILES)'; $self->clean_files('$(O_FILES)'); $self->clean_files('*.stackdump') if $^O eq 'cygwin'; if($self->_xs_debugging()){ # override $Config{optimize} if(_is_msvc()){ $self->makemaker_args->{OPTIMIZE} = '-Zi'; } else{ $self->makemaker_args->{OPTIMIZE} = '-g -ggdb -g3'; } $self->cc_define('-DXS_ASSERT'); } } return; } # GNU C Compiler sub _is_gcc{ return $Config{gccversion}; } # Microsoft Visual C++ Compiler (cl.exe) sub _is_msvc{ return $Config{cc} =~ /\A cl \b /xmsi; } { my $cc_available; sub cc_available { return defined $cc_available ? $cc_available : ($cc_available = shift->can_cc()) ; } # cf. https://github.com/sjn/toolchain-site/blob/219db464af9b2f19b04fec05547ac10180a469f3/lancaster-consensus.md my $want_xs; sub want_xs { my($self, $default) = @_; return $want_xs if defined $want_xs; # you're using this module, you must want XS by default # unless PERL_ONLY is true. $default = !$ENV{PERL_ONLY} if not defined $default; foreach my $arg(@ARGV){ my ($k, $v) = split '=', $arg; # MM-style named args if ($k eq 'PUREPERL_ONLY' && defined $v) { return $want_xs = !$v; } elsif($arg eq '--pp'){ # old-style return $want_xs = 0; } elsif($arg eq '--xs'){ return $want_xs = 1; } } if ($ENV{PERL_MM_OPT}) { my($v) = $ENV{PERL_MM_OPT} =~ /\b PUREPERL_ONLY = (\S+) /xms; if (defined $v) { return $want_xs = !$v; } } return $want_xs = $default; } } sub use_ppport{ my($self, $dppp_version) = @_; return if $self->{_ppport_ok}++; $self->_xs_initialize(); my $filename = 'ppport.h'; $dppp_version ||= 3.19; # the more, the better $self->configure_requires('Devel::PPPort' => $dppp_version); $self->build_requires('Devel::PPPort' => $dppp_version); print "Writing $filename\n"; my $e = do{ local $@; eval qq{ use Devel::PPPort; Devel::PPPort::WriteFile(q{$filename}); }; $@; }; if($e){ print "Cannot create $filename because: $@\n"; } if(-e $filename){ $self->clean_files($filename); $self->cc_define('-DUSE_PPPORT'); $self->cc_append_to_inc('.'); } return; } sub use_xshelper { my($self, $opt) = @_; $self->_xs_initialize(); $self->use_ppport(); my $file = 'xshelper.h'; open my $fh, '>', $file or die "Cannot open $file for writing: $!"; print $fh $self->_xshelper_h(); close $fh or die "Cannot close $file: $!"; if(defined $opt) { if($opt eq '-clean') { $self->clean_files($file); } else { $self->realclean_files($file); } } return; } sub _gccversion { my $res = `$Config{cc} --version`; my ($version) = $res =~ /\(GCC\) ([0-9.]+)/; no warnings 'numeric', 'uninitialized'; return sprintf '%g', $version; } sub cc_warnings{ my($self) = @_; $self->_xs_initialize(); if(_is_gcc()){ $self->cc_append_to_ccflags(qw(-Wall)); my $gccversion = _gccversion(); if($gccversion >= 4.0){ $self->cc_append_to_ccflags(qw(-Wextra)); if(!($UseC99 or $UseCplusplus)) { # Note: MSVC++ doesn't support C99, # so -Wdeclaration-after-statement helps # ensure C89 specs. $self->cc_append_to_ccflags(qw(-Wdeclaration-after-statement)); } if($gccversion >= 4.1 && !$UseCplusplus) { $self->cc_append_to_ccflags(qw(-Wc++-compat)); } } else{ $self->cc_append_to_ccflags(qw(-W -Wno-comment)); } } elsif(_is_msvc()){ $self->cc_append_to_ccflags(qw(-W3)); } else{ # TODO: support other compilers } return; } sub c99_available { my($self) = @_; return 0 if not $self->cc_available(); require File::Temp; require File::Basename; my $tmpfile = File::Temp->new(SUFFIX => '.c'); $tmpfile->print(<<'C99'); // include a C99 header #include inline // a C99 keyword with C99 style comments int test_c99() { int i = 0; i++; int j = i - 1; // another C99 feature: declaration after statement return j; } C99 $tmpfile->close(); system "$Config{cc} -c " . $tmpfile->filename; (my $objname = File::Basename::basename($tmpfile->filename)) =~ s/\Q.c\E$/$Config{_o}/; unlink $objname or warn "Cannot unlink $objname (ignored): $!"; return $? == 0; } sub requires_c99 { my($self) = @_; if(!$self->c99_available) { warn "This distribution requires a C99 compiler, but $Config{cc} seems not to support C99, stopped.\n"; exit; } $self->_xs_initialize(); $UseC99 = 1; return; } sub requires_cplusplus { my($self) = @_; if(!$self->cc_available) { warn "This distribution requires a C++ compiler, but $Config{cc} seems not to support C++, stopped.\n"; exit; } $self->_xs_initialize(); $UseCplusplus = 1; return; } sub cc_append_to_inc{ my($self, @dirs) = @_; $self->_xs_initialize(); for my $dir(@dirs){ unless(-d $dir){ warn("'$dir' not found: $!\n"); } _verbose "inc: -I$dir" if _VERBOSE; } my $mm = $self->makemaker_args; my $paths = join q{ }, map{ s{\\}{\\\\}g; qq{"-I$_"} } @dirs; if($mm->{INC}){ $mm->{INC} .= q{ } . $paths; } else{ $mm->{INC} = $paths; } return; } sub cc_libs { my ($self, @libs) = @_; @libs = map{ my($name, $dir) = ref($_) eq 'ARRAY' ? @{$_} : ($_, undef); my $lib; if(defined $dir) { $lib = ($dir =~ /^-/ ? qq{$dir } : qq{-L$dir }); } else { $lib = ''; } $lib .= ($name =~ /^-/ ? qq{$name} : qq{-l$name}); _verbose "libs: $lib" if _VERBOSE; $lib; } @libs; $self->cc_append_to_libs( @libs ); } sub cc_append_to_libs{ my($self, @libs) = @_; $self->_xs_initialize(); return unless @libs; my $libs = join q{ }, @libs; my $mm = $self->makemaker_args; if ($mm->{LIBS}){ $mm->{LIBS} .= q{ } . $libs; } else{ $mm->{LIBS} = $libs; } return $libs; } sub cc_assert_lib { my ($self, @dcl_args) = @_; if ( ! $self->{xsu_loaded_checklib} ) { my $loaded_lib = 0; foreach my $checklib (qw(inc::Devel::CheckLib Devel::CheckLib)) { eval "use $checklib 0.4"; if (!$@) { $loaded_lib = 1; last; } } if (! $loaded_lib) { warn "Devel::CheckLib not found in inc/ nor \@INC"; exit 0; } $self->{xsu_loaded_checklib}++; $self->configure_requires( "Devel::CheckLib" => "0.4" ); $self->build_requires( "Devel::CheckLib" => "0.4" ); } Devel::CheckLib::check_lib_or_exit(@dcl_args); } sub cc_append_to_ccflags{ my($self, @ccflags) = @_; $self->_xs_initialize(); my $mm = $self->makemaker_args; $mm->{CCFLAGS} ||= $Config{ccflags}; $mm->{CCFLAGS} .= q{ } . join q{ }, @ccflags; return; } sub cc_define{ my($self, @defines) = @_; $self->_xs_initialize(); my $mm = $self->makemaker_args; if(exists $mm->{DEFINE}){ $mm->{DEFINE} .= q{ } . join q{ }, @defines; } else{ $mm->{DEFINE} = join q{ }, @defines; } return; } sub requires_xs_module { my $self = shift; return $self->requires() unless @_; $self->_xs_initialize(); my %added = $self->requires(@_); my(@inc, @libs); my $rx_lib = qr{ \. (?: lib | a) \z}xmsi; my $rx_dll = qr{ \. dll \z}xmsi; # for Cygwin while(my $module = each %added){ my $mod_basedir = File::Spec->join(split /::/, $module); my $rx_header = qr{\A ( .+ \Q$mod_basedir\E ) .+ \. h(?:pp)? \z}xmsi; SCAN_INC: foreach my $inc_dir(@INC){ my @dirs = grep{ -e } File::Spec->join($inc_dir, 'auto', $mod_basedir), File::Spec->join($inc_dir, $mod_basedir); next SCAN_INC unless @dirs; my $n_inc = scalar @inc; find(sub{ if(my($incdir) = $File::Find::name =~ $rx_header){ push @inc, $incdir; } elsif($File::Find::name =~ $rx_lib){ my($libname) = $_ =~ /\A (?:lib)? (\w+) /xmsi; push @libs, [$libname, $File::Find::dir]; } elsif($File::Find::name =~ $rx_dll){ # XXX: hack for Cygwin my $mm = $self->makemaker_args; $mm->{macro}->{PERL_ARCHIVE_AFTER} ||= ''; $mm->{macro}->{PERL_ARCHIVE_AFTER} .= ' ' . $File::Find::name; } }, @dirs); if($n_inc != scalar @inc){ last SCAN_INC; } } } my %uniq = (); $self->cc_append_to_inc (grep{ !$uniq{ $_ }++ } @inc); %uniq = (); $self->cc_libs(grep{ !$uniq{ $_->[0] }++ } @libs); return %added; } sub cc_src_paths{ my($self, @dirs) = @_; $self->_xs_initialize(); return unless @dirs; my $mm = $self->makemaker_args; my $XS_ref = $mm->{XS} ||= {}; my $C_ref = $mm->{C} ||= []; my $_obj = $Config{_o}; my @src_files; find(sub{ if(/ \. (?: xs | c (?: c | pp | xx )? ) \z/xmsi){ # *.{xs, c, cc, cpp, cxx} push @src_files, $File::Find::name; } }, @dirs); my $xs_to = $UseCplusplus ? '.cpp' : '.c'; foreach my $src_file(@src_files){ my $c = $src_file; if($c =~ s/ \.xs \z/$xs_to/xms){ $XS_ref->{$src_file} = $c; _verbose "xs: $src_file" if _VERBOSE; } else{ _verbose "c: $c" if _VERBOSE; } push @{$C_ref}, $c unless grep{ $_ eq $c } @{$C_ref}; } $self->clean_files(map{ File::Spec->catfile($_, '*.gcov'), File::Spec->catfile($_, '*.gcda'), File::Spec->catfile($_, '*.gcno'), } @dirs); $self->cc_append_to_inc('.'); return; } sub cc_include_paths{ my($self, @dirs) = @_; $self->_xs_initialize(); push @{ $self->{xsu_include_paths} ||= []}, @dirs; my $h_map = $self->{xsu_header_map} ||= {}; foreach my $dir(@dirs){ my $prefix = quotemeta( File::Spec->catfile($dir, '') ); find(sub{ return unless / \.h(?:pp)? \z/xms; (my $h_file = $File::Find::name) =~ s/ \A $prefix //xms; $h_map->{$h_file} = $File::Find::name; }, $dir); } $self->cc_append_to_inc(@dirs); return; } sub install_headers{ my $self = shift; my $h_files; if(@_ == 0){ $h_files = $self->{xsu_header_map} or die "install_headers: cc_include_paths not specified.\n"; } elsif(@_ == 1 && ref($_[0]) eq 'HASH'){ $h_files = $_[0]; } else{ $h_files = +{ map{ $_ => undef } @_ }; } $self->_xs_initialize(); my @not_found; my $h_map = $self->{xsu_header_map} || {}; while(my($ident, $path) = each %{$h_files}){ $path ||= $h_map->{$ident} || File::Spec->join('.', $ident); $path = File::Spec->canonpath($path); unless($path && -e $path){ push @not_found, $ident; next; } $ToInstall{$path} = File::Spec->join('$(INST_ARCHAUTODIR)', $ident); _verbose "install: $path as $ident" if _VERBOSE; my @funcs = $self->_extract_functions_from_header_file($path); if(@funcs){ $self->cc_append_to_funclist(@funcs); } } if(@not_found){ die "Header file(s) not found: @not_found\n"; } return; } my $home_directory; sub _extract_functions_from_header_file{ my($self, $h_file) = @_; my @functions; ($home_directory) = <~> unless defined $home_directory; # get header file contents through cpp(1) my $contents = do { my $mm = $self->makemaker_args; my $cppflags = q{"-I}. File::Spec->join($Config{archlib}, 'CORE') . q{"}; $cppflags =~ s/~/$home_directory/g; $cppflags .= ' ' . $mm->{INC} if $mm->{INC}; $cppflags .= ' ' . ($mm->{CCFLAGS} || $Config{ccflags}); $cppflags .= ' ' . $mm->{DEFINE} if $mm->{DEFINE}; my $add_include = _is_msvc() ? '-FI' : '-include'; $cppflags .= ' ' . join ' ', map{ qq{$add_include "$_"} } qw(EXTERN.h perl.h XSUB.h); my $cppcmd = qq{$Config{cpprun} $cppflags $h_file}; # remove all the -arch options to workaround gcc errors: # "-E, -S, -save-temps and -M options are not allowed # with multiple -arch flags" $cppcmd =~ s/ -arch \s* \S+ //xmsg; _verbose("extract functions from: $cppcmd") if _VERBOSE; `$cppcmd`; }; unless(defined $contents){ die "Cannot call C pre-processor ($Config{cpprun}): $! ($?)"; } # remove other include file contents my $chfile = q/\# (?:line)? \s+ \d+ /; $contents =~ s{ ^$chfile \s+ (?!"\Q$h_file\E") .*? ^(?= $chfile) }{}xmsig; if(_VERBOSE){ local *H; open H, "> $h_file.out" and print H $contents and close H; } while($contents =~ m{ ([^\\;\s]+ # type \s+ ([a-zA-Z_][a-zA-Z0-9_]*) # function name \s* \( [^;#]* \) # argument list [\w\s\(\)]* # attributes or something ;) # end of declaration }xmsg){ my $decl = $1; my $name = $2; next if $decl =~ /\b typedef \b/xms; next if $name =~ /^_/xms; # skip something private push @functions, $name; if(_VERBOSE){ $decl =~ tr/\n\r\t / /s; $decl =~ s/ (\Q$name\E) /<$name>/xms; _verbose("decl: $decl"); } } return @functions; } sub cc_append_to_funclist{ my($self, @functions) = @_; $self->_xs_initialize(); my $mm = $self->makemaker_args; push @{$mm->{FUNCLIST} ||= []}, @functions; $mm->{DL_FUNCS} ||= { '$(NAME)' => [] }; return; } sub _xshelper_h { my $h = <<'XSHELPER_H'; :/* THIS FILE IS AUTOMATICALLY GENERATED BY Module::Install::XSUtil $VERSION. */ :/* :=head1 NAME : :xshelper.h - Helper C header file for XS modules : :=head1 DESCRIPTION : : // This includes all the perl header files and ppport.h : #include "xshelper.h" : :=head1 SEE ALSO : :L, where this file is distributed as a part of : :=head1 AUTHOR : :Fuji, Goro (gfx) Egfuji at cpan.orgE : :=head1 LISENCE : :Copyright (c) 2010, Fuji, Goro (gfx). All rights reserved. : :This library is free software; you can redistribute it and/or modify :it under the same terms as Perl itself. : :=cut :*/ : :#ifdef __cplusplus :extern "C" { :#endif : :#define PERL_NO_GET_CONTEXT /* we want efficiency */ :#include :#include :#define NO_XSLOCKS /* for exceptions */ :#include : :#ifdef __cplusplus :} /* extern "C" */ :#endif : :#include "ppport.h" : :/* portability stuff not supported by ppport.h yet */ : :#ifndef STATIC_INLINE /* from 5.13.4 */ :# if defined(__GNUC__) || defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) :# define STATIC_INLINE static inline :# else :# define STATIC_INLINE static :# endif :#endif /* STATIC_INLINE */ : :#ifndef __attribute__format__ :#define __attribute__format__(a,b,c) /* nothing */ :#endif : :#ifndef LIKELY /* they are just a compiler's hint */ :#define LIKELY(x) (!!(x)) :#define UNLIKELY(x) (!!(x)) :#endif : :#ifndef newSVpvs_share :#define newSVpvs_share(s) Perl_newSVpvn_share(aTHX_ STR_WITH_LEN(s), 0U) :#endif : :#ifndef get_cvs :#define get_cvs(name, flags) get_cv(name, flags) :#endif : :#ifndef GvNAME_get :#define GvNAME_get GvNAME :#endif :#ifndef GvNAMELEN_get :#define GvNAMELEN_get GvNAMELEN :#endif : :#ifndef CvGV_set :#define CvGV_set(cv, gv) (CvGV(cv) = (gv)) :#endif : :/* general utility */ : :#if PERL_BCDVERSION >= 0x5008005 :#define LooksLikeNumber(x) looks_like_number(x) :#else :#define LooksLikeNumber(x) (SvPOKp(x) ? looks_like_number(x) : (I32)SvNIOKp(x)) :#endif : :#define newAV_mortal() (AV*)sv_2mortal((SV*)newAV()) :#define newHV_mortal() (HV*)sv_2mortal((SV*)newHV()) :#define newRV_inc_mortal(sv) sv_2mortal(newRV_inc(sv)) :#define newRV_noinc_mortal(sv) sv_2mortal(newRV_noinc(sv)) : :#define DECL_BOOT(name) EXTERN_C XS(CAT2(boot_, name)) :#define CALL_BOOT(name) STMT_START { \ : PUSHMARK(SP); \ : CALL_FPTR(CAT2(boot_, name))(aTHX_ cv); \ : } STMT_END XSHELPER_H $h =~ s/^://xmsg; $h =~ s/\$VERSION\b/$Module::Install::XSUtil::VERSION/xms; return $h; } package MY; # XXX: We must append to PM inside ExtUtils::MakeMaker->new(). sub init_PM { my $self = shift; $self->SUPER::init_PM(@_); while(my($k, $v) = each %ToInstall){ $self->{PM}{$k} = $v; } return; } # append object file names to CCCMD sub const_cccmd { my $self = shift; my $cccmd = $self->SUPER::const_cccmd(@_); return q{} unless $cccmd; if (Module::Install::XSUtil::_is_msvc()){ $cccmd .= ' -Fo$@'; } else { $cccmd .= ' -o $@'; } return $cccmd } sub xs_c { my($self) = @_; my $mm = $self->SUPER::xs_c(); $mm =~ s/ \.c /.cpp/xmsg if $UseCplusplus; return $mm; } sub xs_o { my($self) = @_; my $mm = $self->SUPER::xs_o(); $mm =~ s/ \.c /.cpp/xmsg if $UseCplusplus; return $mm; } 1; __END__ #line 1030