LCOV - code coverage report
Current view: top level - dns - name.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 301 304 99.0 %
Date: 2012-05-15 Functions: 19 19 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 266 389 68.4 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #include <cctype>
      16                 :            : #include <cassert>
      17                 :            : #include <iterator>
      18                 :            : #include <functional>
      19                 :            : #include <vector>
      20                 :            : #include <iostream>
      21                 :            : #include <algorithm>
      22                 :            : 
      23                 :            : #include <util/buffer.h>
      24                 :            : #include <dns/exceptions.h>
      25                 :            : #include <dns/name.h>
      26                 :            : #include <dns/name_internal.h>
      27                 :            : #include <dns/messagerenderer.h>
      28                 :            : 
      29                 :            : using namespace std;
      30                 :            : using namespace isc::util;
      31                 :            : using isc::dns::NameComparisonResult;
      32                 :            : using namespace isc::dns::name::internal;
      33                 :            : 
      34                 :            : namespace isc {
      35                 :            : namespace dns {
      36                 :            : 
      37                 :            : namespace {
      38                 :            : ///
      39                 :            : /// These are shortcut arrays for efficient character conversion.
      40                 :            : /// digitvalue converts a digit character to the corresponding integer.
      41                 :            : /// maptolower convert uppercase alphabets to their lowercase counterparts.
      42                 :            : /// We once used a helper non-local static object to avoid hardcoding the
      43                 :            : /// array members, but we then realized it's susceptible to static
      44                 :            : /// initialization order fiasco: Since these constants are used in a Name
      45                 :            : /// constructor, a non-local static Name object defined in another translation
      46                 :            : /// unit than this file may not be initialized correctly.
      47                 :            : /// There are several ways to address this issue, but in this specific case
      48                 :            : /// we chose the naive but simple hardcoding approach.
      49                 :            : ///
      50                 :            : /// These definitions are derived from BIND 9's libdns module.
      51                 :            : /// Note: we could use the standard tolower() function instead of the
      52                 :            : /// maptolower array, but a benchmark indicated that the private array could
      53                 :            : /// improve the performance of message rendering (which internally uses the
      54                 :            : /// array heavily) about 27%.  Since we want to achieve very good performance
      55                 :            : /// for message rendering in some cases, we'll keep using it.
      56                 :            : const char digitvalue[256] = {
      57                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16
      58                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32
      59                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 48
      60                 :            :      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, // 64
      61                 :            :     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
      62                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96
      63                 :            :     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 112
      64                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128
      65                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      66                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      67                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      68                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      69                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      70                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      71                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      72                 :            :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 256
      73                 :            : };
      74                 :            : }
      75                 :            : 
      76                 :            : namespace name {
      77                 :            : namespace internal {
      78                 :            : const unsigned char maptolower[] = {
      79                 :            :     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
      80                 :            :     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
      81                 :            :     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
      82                 :            :     0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
      83                 :            :     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
      84                 :            :     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
      85                 :            :     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
      86                 :            :     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
      87                 :            :     0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // ..., 'A' - 'G'
      88                 :            :     0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, // 'H' - 'O'
      89                 :            :     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // 'P' - 'W'
      90                 :            :     0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, // 'X' - 'Z', ...
      91                 :            :     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
      92                 :            :     0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
      93                 :            :     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
      94                 :            :     0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
      95                 :            :     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
      96                 :            :     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
      97                 :            :     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
      98                 :            :     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
      99                 :            :     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
     100                 :            :     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
     101                 :            :     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
     102                 :            :     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
     103                 :            :     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
     104                 :            :     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
     105                 :            :     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
     106                 :            :     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
     107                 :            :     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
     108                 :            :     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
     109                 :            :     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
     110                 :            :     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
     111                 :            : };
     112                 :            : } // end of internal
     113                 :            : } // end of name
     114                 :            : 
     115                 :            : namespace {
     116                 :            : ///
     117                 :            : /// Textual name parser states.
     118                 :            : ///
     119                 :            : typedef enum {
     120                 :            :     ft_init = 0,                // begin of the name
     121                 :            :     ft_start,                   // begin of a label
     122                 :            :     ft_ordinary,                // parsing an ordinary label
     123                 :            :     ft_initialescape,           // just found '\'
     124                 :            :     ft_escape,                  // begin of handling a '\'-escaped sequence
     125                 :            :     ft_escdecimal,              // parsing a '\DDD' octet.
     126                 :            : 
     127                 :            :     // Unused at this moment.  We'll revisit this when we support master file
     128                 :            :     // parser where @ is used to mean an origin name.
     129                 :            :     ft_at                  
     130                 :            : } ft_state;
     131                 :            : }
     132                 :            : 
     133                 :         49 : Name::Name(const std::string &namestring, bool downcase) {
     134                 :            :     //
     135                 :            :     // Initialize things to make the compiler happy; they're not required.
     136                 :            :     //
     137                 :     290959 :     unsigned int digits = 0;
     138                 :     290959 :     unsigned int value = 0;
     139                 :     290959 :     unsigned int count = 0;
     140                 :            : 
     141                 :            :     //
     142                 :            :     // Set up the state machine.
     143                 :            :     //
     144                 :     290959 :     std::string::const_iterator s = namestring.begin();
     145                 :     290959 :     std::string::const_iterator send = namestring.end();
     146                 :     290959 :     bool done = false;
     147                 :     290959 :     bool is_root = false;
     148                 :     290959 :     ft_state state = ft_init;
     149                 :            : 
     150                 :            :     std::vector<unsigned char> offsets;
     151         [ +  - ]:     290959 :     offsets.reserve(Name::MAX_LABELS);
     152         [ +  - ]:     290959 :     offsets.push_back(0);
     153                 :            : 
     154                 :     290959 :     std::string ndata;
     155         [ +  - ]:     290959 :     ndata.reserve(Name::MAX_WIRE);
     156                 :            : 
     157                 :            :     // should we refactor this code using, e.g, the state pattern?  Probably
     158                 :            :     // not at this point, as this is based on proved code (derived from BIND9)
     159                 :            :     // and it's less likely that we'll have more variations in the domain name
     160                 :            :     // syntax.  If this ever happens next time, we should consider refactor
     161                 :            :     // the code, rather than adding more states and cases below.
     162 [ +  + ][ +  + ]:    6130265 :     while (ndata.size() < Name::MAX_WIRE && s != send && !done) {
         [ -  + ][ +  + ]
     163                 :    5839347 :         unsigned char c = *s++;
     164                 :            : 
     165   [ +  +  +  +  :    5839347 :         switch (state) {
                +  +  - ]
     166                 :            :         case ft_init:
     167                 :            :             //
     168                 :            :             // Is this the root name?
     169                 :            :             //
     170         [ +  + ]:     290957 :             if (c == '.') {
     171         [ +  + ]:       7270 :                 if (s != send) {
     172 [ +  - ][ +  - ]:          8 :                     isc_throw(EmptyLabel,
                 [ +  - ]
     173                 :            :                               "non terminating empty label in " << namestring);
     174                 :            :                 }
     175                 :            :                 is_root = true;
     176 [ +  + ][ -  + ]:     283687 :             } else if (c == '@' && s == send) {
                 [ +  + ]
     177                 :            :                 // handle a single '@' as the root name.
     178                 :          1 :                 is_root = true;
     179                 :            :             }
     180                 :            : 
     181         [ +  + ]:     290953 :             if (is_root) {
     182         [ +  - ]:       7267 :                 ndata.push_back(0);
     183                 :            :                 done = true;
     184                 :            :                 break;
     185                 :            :             }
     186                 :            : 
     187                 :            :             // FALLTHROUGH
     188                 :            :         case ft_start:
     189         [ +  - ]:     905596 :             ndata.push_back(0); // placeholder for the label length field
     190                 :     905596 :             count = 0;
     191         [ +  + ]:     905596 :             if (c == '\\') {
     192                 :            :                 state = ft_initialescape;
     193                 :            :                 break;
     194                 :            :             }
     195                 :     905573 :             state = ft_ordinary;
     196         [ -  + ]:     905573 :             assert(ndata.size() < Name::MAX_WIRE);
     197                 :            :             // FALLTHROUGH
     198                 :            :         case ft_ordinary:
     199         [ +  + ]:    5830621 :             if (c == '.') {
     200         [ +  + ]:     890273 :                 if (count == 0) {
     201 [ +  - ][ +  - ]:         32 :                     isc_throw(EmptyLabel,
                 [ +  - ]
     202                 :            :                               "duplicate period in " << namestring);
     203                 :            :                 }
     204         [ +  - ]:     890257 :                 ndata.at(offsets.back()) = count;
     205         [ +  - ]:     890257 :                 offsets.push_back(ndata.size());
     206         [ +  + ]:     890257 :                 if (s == send) {
     207         [ +  - ]:     268347 :                     ndata.push_back(0);
     208                 :            :                     done = true;
     209                 :            :                 }
     210                 :            :                 state = ft_start;
     211         [ +  + ]:    4940348 :             } else if (c == '\\') {
     212                 :            :                 state = ft_escape;
     213                 :            :             } else {
     214         [ +  + ]:    4939884 :                 if (++count > MAX_LABELLEN) {
     215 [ +  - ][ +  - ]:         18 :                     isc_throw(TooLongLabel,
                 [ +  - ]
     216                 :            :                               "label is too long in " << namestring);
     217                 :            :                 }
     218 [ +  + ][ +  - ]:    4939875 :                 ndata.push_back(downcase ? maptolower[c] : c);
     219                 :            :             }
     220                 :            :             break;
     221                 :            :         case ft_initialescape:
     222         [ +  + ]:         22 :             if (c == '[') {
     223                 :            :                 // This looks like a bitstring label, which was deprecated.
     224                 :            :                 // Intentionally drop it.
     225 [ +  - ][ +  - ]:          6 :                 isc_throw(BadLabelType,
                 [ +  - ]
     226                 :            :                           "invalid label type in " << namestring);
     227                 :            :             }
     228                 :            :             state = ft_escape;
     229                 :            :             // FALLTHROUGH
     230                 :            :         case ft_escape:
     231         [ +  + ]:        483 :             if (!isdigit(c & 0xff)) {
     232         [ +  + ]:          9 :                 if (++count > MAX_LABELLEN) {
     233 [ +  - ][ +  - ]:          4 :                     isc_throw(TooLongLabel,
                 [ +  - ]
     234                 :            :                               "label is too long in " << namestring);
     235                 :            :                 }
     236 [ -  + ][ +  - ]:          7 :                 ndata.push_back(downcase ? maptolower[c] : c);
     237                 :            :                 state = ft_ordinary;
     238                 :            :                 break;
     239                 :            :             }
     240                 :            :             digits = 0;
     241                 :            :             value = 0;
     242                 :            :             state = ft_escdecimal;
     243                 :            :             // FALLTHROUGH
     244                 :            :         case ft_escdecimal:
     245         [ +  + ]:       1420 :             if (!isdigit(c & 0xff)) {
     246 [ +  - ][ +  - ]:          4 :                 isc_throw(BadEscape,
                 [ +  - ]
     247                 :            :                           "mixture of escaped digit and non-digit in "
     248                 :            :                           << namestring);
     249                 :            :             }
     250                 :       1418 :             value *= 10;
     251                 :       1418 :             value += digitvalue[c];
     252                 :       1418 :             digits++;
     253         [ +  + ]:       1418 :             if (digits == 3) {
     254         [ +  + ]:        470 :                 if (value > 255) {
     255 [ +  - ][ +  - ]:          6 :                     isc_throw(BadEscape,
                 [ +  - ]
     256                 :            :                               "escaped decimal is too large in "
     257                 :            :                               << namestring);
     258                 :            :                 }
     259         [ +  + ]:        467 :                 if (++count > MAX_LABELLEN) {
     260 [ +  - ][ +  - ]:          4 :                     isc_throw(TooLongLabel,
                 [ +  - ]
     261                 :            :                               "label is too long in " << namestring);
     262                 :            :                 }
     263 [ +  + ][ +  - ]:        465 :                 ndata.push_back(downcase ? maptolower[value] : value);
     264                 :            :                 state = ft_ordinary;
     265                 :            :             }
     266                 :            :             break;
     267                 :            :         default:
     268                 :            :             // impossible case
     269                 :    5839306 :             assert(false);
     270                 :            :         }
     271                 :            :     }
     272                 :            : 
     273         [ +  + ]:     290918 :     if (!done) {                // no trailing '.' was found.
     274         [ +  + ]:      15304 :         if (ndata.size() == Name::MAX_WIRE) {
     275 [ +  - ][ +  - ]:          6 :             isc_throw(TooLongName,
                 [ +  - ]
     276                 :            :                       "name is too long for termination in " << namestring);
     277                 :            :         }
     278         [ -  + ]:      15301 :         assert(s == send);
     279         [ +  + ]:      15301 :         if (state != ft_ordinary && state != ft_at) {
     280 [ +  - ][ +  + ]:         10 :             isc_throw(IncompleteName,
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     281                 :            :                       "incomplete textual name in " <<
     282                 :            :                       (namestring.empty() ? "<empty>" : namestring));
     283                 :            :         }
     284         [ +  - ]:      15296 :         if (state == ft_ordinary) {
     285         [ -  + ]:      15296 :             assert(count != 0);
     286         [ +  - ]:      15296 :             ndata.at(offsets.back()) = count;
     287                 :            : 
     288         [ +  - ]:      15296 :             offsets.push_back(ndata.size());
     289                 :            :             // add a trailing \0
     290         [ +  - ]:      15296 :             ndata.push_back('\0');
     291                 :            :         }
     292                 :            :     }
     293                 :            : 
     294                 :     581820 :     labelcount_ = offsets.size();
     295         [ -  + ]:     290910 :     assert(labelcount_ > 0 && labelcount_ <= Name::MAX_LABELS);
     296         [ +  - ]:     290910 :     ndata_.assign(ndata.data(), ndata.size());
     297                 :     581820 :     length_ = ndata_.size();
     298                 :     290910 :     offsets_.assign(offsets.begin(), offsets.end());
     299                 :     290910 : }
     300                 :            : 
     301                 :            : namespace {
     302                 :            : ///
     303                 :            : /// Wire-format name parser states.
     304                 :            : ///
     305                 :            : typedef enum {
     306                 :            :     fw_start = 0,               // beginning of a label
     307                 :            :     fw_ordinary,                // inside an ordinary (non compressed) label
     308                 :            :     fw_newcurrent               // beginning of a compression pointer
     309                 :            : } fw_state;
     310                 :            : }
     311                 :            : 
     312                 :         25 : Name::Name(InputBuffer& buffer, bool downcase) {
     313                 :            :     std::vector<unsigned char> offsets;
     314         [ +  - ]:       3607 :     offsets.reserve(Name::MAX_LABELS);
     315                 :            : 
     316                 :            :     /*
     317                 :            :      * Initialize things to make the compiler happy; they're not required.
     318                 :            :      */
     319                 :       3607 :     unsigned int n = 0;
     320                 :            : 
     321                 :            :     //
     322                 :            :     // Set up.
     323                 :            :     //
     324                 :       3607 :     bool done = false;
     325                 :       3607 :     unsigned int nused = 0;
     326                 :       3607 :     bool seen_pointer = false;
     327                 :       3607 :     fw_state state = fw_start;
     328                 :            : 
     329                 :       3607 :     unsigned int cused = 0;     // Bytes of compressed name data used
     330                 :       3607 :     unsigned int current = buffer.getPosition();
     331                 :       3607 :     unsigned int pos_begin = current;
     332                 :       3607 :     unsigned int biggest_pointer = current;
     333                 :            : 
     334                 :            :     // Make the compiler happy; this is not required.
     335                 :            :     // XXX: bad style in that we initialize it with a dummy value and define
     336                 :            :     // it far from where it's used.  But alternatives seemed even worse.
     337                 :       3607 :     unsigned int new_current = 0;
     338                 :            : 
     339                 :            :     //
     340                 :            :     // Note:  The following code is not optimized for speed, but
     341                 :            :     // rather for correctness.  Speed will be addressed in the future.
     342                 :            :     //
     343 [ +  + ][ +  + ]:      63748 :     while (current < buffer.getLength() && !done) {
                 [ +  + ]
     344                 :      60158 :         unsigned int c = buffer.readUint8();
     345                 :      60158 :         current++;
     346         [ +  + ]:      60158 :         if (!seen_pointer) {
     347                 :      32013 :             cused++;
     348                 :            :         }
     349                 :            : 
     350   [ +  +  +  - ]:      60158 :         switch (state) {
     351                 :            :         case fw_start:
     352         [ +  + ]:      15226 :             if (c <= MAX_LABELLEN) {
     353         [ +  - ]:      12585 :                 offsets.push_back(nused);
     354         [ +  + ]:      12585 :                 if (nused + c + 1 > Name::MAX_WIRE) {
     355 [ +  - ][ +  - ]:          9 :                     isc_throw(DNSMessageFORMERR, "wire name is too long: "
                 [ +  - ]
     356                 :            :                               << nused + c + 1 << " bytes");
     357                 :            :                 }
     358                 :      12582 :                 nused += c + 1;
     359         [ +  - ]:      12582 :                 ndata_.push_back(c);
     360         [ +  + ]:      12582 :                 if (c == 0) {
     361                 :       3582 :                     done = true;
     362                 :            :                 }
     363                 :      12582 :                 n = c;
     364                 :      12582 :                 state = fw_ordinary;
     365         [ +  + ]:       2641 :             } else if ((c & COMPRESS_POINTER_MARK8) == COMPRESS_POINTER_MARK8) {
     366                 :            :                 //
     367                 :            :                 // Ordinary 14-bit pointer.
     368                 :            :                 //
     369                 :       2632 :                 new_current = c & ~COMPRESS_POINTER_MARK8;
     370                 :       2632 :                 n = 1;
     371                 :       2632 :                 state = fw_newcurrent;
     372                 :            :             } else {
     373                 :            :                 // this case includes local compression pointer, which hasn't
     374                 :            :                 // been standardized.
     375 [ +  - ][ +  - ]:         27 :                 isc_throw(DNSMessageFORMERR, "unknown label character: " << c);
     376                 :            :             }
     377                 :            :             break;
     378                 :            :         case fw_ordinary:
     379         [ +  + ]:      42301 :             if (downcase) {
     380                 :          6 :                 c = maptolower[c];
     381                 :            :             }
     382         [ +  - ]:      42301 :             ndata_.push_back(c);
     383         [ +  + ]:      42301 :             if (--n == 0) {
     384                 :       9000 :                 state = fw_start;
     385                 :            :             }
     386                 :            :             break;
     387                 :            :         case fw_newcurrent:
     388                 :       2631 :             new_current *= 256;
     389                 :       2631 :             new_current += c;
     390         [ +  - ]:       2631 :             if (--n != 0) {
     391                 :            :                 break;
     392                 :            :             }
     393         [ +  + ]:       2631 :             if (new_current >= biggest_pointer) {
     394 [ +  - ][ +  - ]:         15 :                 isc_throw(DNSMessageFORMERR,
     395                 :            :                           "bad compression pointer (out of range): " <<
     396                 :            :                           new_current);
     397                 :            :             }
     398                 :       2626 :             biggest_pointer = new_current;
     399                 :       2626 :             current = new_current;
     400                 :       2626 :             buffer.setPosition(current);
     401                 :       2626 :             seen_pointer = true;
     402                 :       2626 :             state = fw_start;
     403                 :       2626 :             break;
     404                 :            :         default:
     405                 :      60141 :             assert(false);
     406                 :            :         }
     407                 :            :     }
     408                 :            : 
     409         [ +  + ]:       3590 :     if (!done) {
     410 [ +  - ][ +  - ]:         16 :         isc_throw(DNSMessageFORMERR, "incomplete wire-format name");
     411                 :            :     }
     412                 :            : 
     413                 :       7164 :     labelcount_ = offsets.size();
     414                 :       3582 :     length_ = nused;
     415                 :       3582 :     offsets_.assign(offsets.begin(), offsets.end());
     416                 :       3582 :     buffer.setPosition(pos_begin + cused);
     417                 :       3582 : }
     418                 :            : 
     419                 :            : void
     420                 :        572 : Name::toWire(OutputBuffer& buffer) const {
     421                 :       1716 :     buffer.writeData(ndata_.data(), ndata_.size());
     422                 :        572 : }
     423                 :            : 
     424                 :            : void
     425                 :        652 : Name::toWire(AbstractMessageRenderer& renderer) const {
     426                 :        652 :     renderer.writeName(*this);
     427                 :        652 : }
     428                 :            : 
     429                 :            : std::string
     430                 :      41821 : Name::toText(bool omit_final_dot) const {
     431         [ +  + ]:      41821 :     if (length_ == 1) {
     432                 :            :         //
     433                 :            :         // Special handling for the root label.  We ignore omit_final_dot.
     434                 :            :         //
     435 [ +  - ][ -  + ]:        673 :         assert(labelcount_ == 1 && ndata_[0] == '\0');
     436                 :        673 :         return (".");
     437                 :            :     }
     438                 :            : 
     439                 :      82296 :     std::string::const_iterator np = ndata_.begin();
     440                 :      82296 :     std::string::const_iterator np_end = ndata_.end();
     441                 :      41148 :     unsigned int labels = labelcount_; // use for integrity check
     442                 :            :     // init with an impossible value to catch error cases in the end:
     443                 :      41148 :     unsigned int count = MAX_LABELLEN + 1;
     444                 :            : 
     445                 :            :     // result string: it will roughly have the same length as the wire format
     446                 :            :     // name data.  reserve that length to minimize reallocation.
     447                 :      41821 :     std::string result;
     448         [ +  - ]:      41148 :     result.reserve(length_);
     449                 :            : 
     450         [ +  - ]:     155333 :     while (np != np_end) {
     451                 :     155333 :         labels--;
     452                 :     155333 :         count = *np++;
     453                 :            : 
     454         [ +  + ]:     155333 :         if (count == 0) {
     455         [ +  + ]:      41148 :             if (!omit_final_dot) {
     456         [ +  - ]:      40573 :                 result.push_back('.');
     457                 :            :             }
     458                 :            :             break;
     459                 :            :         }
     460                 :            :             
     461         [ +  - ]:     114185 :         if (count <= MAX_LABELLEN) {
     462         [ -  + ]:     114185 :             assert(np_end - np >= count);
     463                 :            : 
     464         [ +  + ]:     187222 :             if (!result.empty()) {
     465                 :            :                 // just after a non-empty label.  add a separating dot.
     466         [ +  - ]:      73037 :                 result.push_back('.');
     467                 :            :             }
     468                 :            : 
     469         [ +  + ]:     697811 :             while (count-- > 0) {
     470                 :     583626 :                 unsigned char c = *np++;
     471         [ +  + ]:     583626 :                 switch (c) {
     472                 :            :                 case 0x22: // '"'
     473                 :            :                 case 0x28: // '('
     474                 :            :                 case 0x29: // ')'
     475                 :            :                 case 0x2E: // '.'
     476                 :            :                 case 0x3B: // ';'
     477                 :            :                 case 0x5C: // '\\'
     478                 :            :                     // Special modifiers in zone files.
     479                 :            :                 case 0x40: // '@'
     480                 :            :                 case 0x24: // '$'
     481         [ +  - ]:         38 :                     result.push_back('\\');
     482         [ +  - ]:         38 :                     result.push_back(c);
     483                 :            :                     break;
     484                 :            :                 default:
     485         [ +  + ]:     583588 :                     if (c > 0x20 && c < 0x7f) {
     486                 :            :                         // append printable characters intact
     487         [ +  - ]:     583425 :                         result.push_back(c);
     488                 :            :                     } else {
     489                 :            :                         // encode non-printable characters in the form of \DDD
     490         [ +  - ]:        163 :                         result.push_back(0x5c);
     491         [ +  - ]:        163 :                         result.push_back(0x30 + ((c / 100) % 10));
     492         [ +  - ]:        163 :                         result.push_back(0x30 + ((c / 10) % 10));
     493         [ +  - ]:     583626 :                         result.push_back(0x30 + (c % 10));
     494                 :            :                     }
     495                 :            :                 }
     496                 :            :             }
     497                 :            :         } else {
     498 [ #  # ][ #  # ]:      41148 :             isc_throw(BadLabelType, "unknown label type in name data");
     499                 :            :         }
     500                 :            :     }
     501                 :            : 
     502         [ -  + ]:      41148 :     assert(labels == 0);
     503         [ -  + ]:      41148 :     assert(count == 0);         // a valid name must end with a 'dot'.
     504                 :            : 
     505         [ +  - ]:      41148 :     return (result);
     506                 :            : }
     507                 :            : 
     508                 :            : NameComparisonResult
     509                 :     204233 : Name::compare(const Name& other) const {
     510                 :            :     // Determine the relative ordering under the DNSSEC order relation of
     511                 :            :     // 'this' and 'other', and also determine the hierarchical relationship
     512                 :            :     // of the names.
     513                 :            : 
     514                 :     204233 :     unsigned int nlabels = 0;
     515                 :     204233 :     unsigned int l1 = labelcount_;
     516                 :     204233 :     unsigned int l2 = other.labelcount_;
     517                 :     204233 :     int ldiff = (int)l1 - (int)l2;
     518         [ +  + ]:     204233 :     unsigned int l = (ldiff < 0) ? l1 : l2;
     519                 :            : 
     520         [ +  + ]:     786367 :     while (l > 0) {
     521                 :     727953 :         --l;
     522                 :     727953 :         --l1;
     523                 :     727953 :         --l2;
     524                 :    1455906 :         size_t pos1 = offsets_[l1];
     525                 :    1455906 :         size_t pos2 = other.offsets_[l2];
     526                 :    1455906 :         unsigned int count1 = ndata_[pos1++];
     527                 :    1455906 :         unsigned int count2 = other.ndata_[pos2++];
     528                 :            : 
     529                 :            :         // We don't support any extended label types including now-obsolete
     530                 :            :         // bitstring labels.
     531         [ -  + ]:     727953 :         assert(count1 <= MAX_LABELLEN && count2 <= MAX_LABELLEN);
     532                 :            : 
     533                 :     727953 :         int cdiff = (int)count1 - (int)count2;
     534         [ +  + ]:     727953 :         unsigned int count = (cdiff < 0) ? count1 : count2;
     535                 :            : 
     536         [ +  + ]:    2732383 :         while (count > 0) {
     537                 :    4285854 :             unsigned char label1 = ndata_[pos1];
     538                 :    4285854 :             unsigned char label2 = other.ndata_[pos2];
     539                 :            : 
     540                 :    2142927 :             int chdiff = (int)maptolower[label1] - (int)maptolower[label2];
     541         [ +  + ]:    2142927 :             if (chdiff != 0) {
     542                 :            :                 return (NameComparisonResult(chdiff, nlabels,
     543                 :     138497 :                                          NameComparisonResult::COMMONANCESTOR));
     544                 :            :             }
     545                 :    2004430 :             --count;
     546                 :    2004430 :             ++pos1;
     547                 :    2004430 :             ++pos2;
     548                 :            :         }
     549         [ +  + ]:     589456 :         if (cdiff != 0) {
     550                 :            :                 return (NameComparisonResult(cdiff, nlabels,
     551                 :       7322 :                                          NameComparisonResult::COMMONANCESTOR));
     552                 :            :         }
     553                 :     582134 :         ++nlabels;
     554                 :            :     }
     555                 :            : 
     556         [ +  + ]:      58414 :     if (ldiff < 0) {
     557                 :            :         return (NameComparisonResult(ldiff, nlabels,
     558                 :       8473 :                                      NameComparisonResult::SUPERDOMAIN));
     559         [ +  + ]:      49941 :     } else if (ldiff > 0) {
     560                 :            :         return (NameComparisonResult(ldiff, nlabels,
     561                 :      39050 :                                      NameComparisonResult::SUBDOMAIN));
     562                 :            :     }
     563                 :            : 
     564                 :     204233 :     return (NameComparisonResult(ldiff, nlabels, NameComparisonResult::EQUAL));
     565                 :            : }
     566                 :            : 
     567                 :            : bool
     568                 :      24978 : Name::equals(const Name& other) const {
     569         [ +  + ]:      24978 :     if (length_ != other.length_ || labelcount_ != other.labelcount_) {
     570                 :            :         return (false);
     571                 :            :     }
     572                 :            : 
     573         [ +  + ]:      55368 :     for (unsigned int l = labelcount_, pos = 0; l > 0; --l) {
     574                 :      60780 :         unsigned char count = ndata_[pos];
     575         [ +  - ]:      30390 :         if (count != other.ndata_[pos]) {
     576                 :            :             return (false);
     577                 :            :         }
     578                 :      30390 :         ++pos;
     579                 :            : 
     580         [ +  + ]:     137477 :         while (count-- > 0) {
     581                 :     216976 :             unsigned char label1 = ndata_[pos];
     582                 :     216976 :             unsigned char label2 = other.ndata_[pos];
     583                 :            : 
     584         [ +  + ]:     108488 :             if (maptolower[label1] != maptolower[label2]) {
     585                 :            :                 return (false);
     586                 :            :             }
     587                 :     107087 :             ++pos;
     588                 :            :         }
     589                 :            :     }
     590                 :            : 
     591                 :            :     return (true);
     592                 :            : }
     593                 :            : 
     594                 :            : bool
     595                 :          9 : Name::leq(const Name& other) const {
     596                 :          9 :     return (compare(other).getOrder() <= 0);
     597                 :            : }
     598                 :            : 
     599                 :            : bool
     600                 :          9 : Name::geq(const Name& other) const {
     601                 :          9 :     return (compare(other).getOrder() >= 0);
     602                 :            : }
     603                 :            : 
     604                 :            : bool
     605                 :      44381 : Name::lthan(const Name& other) const {
     606                 :      44381 :     return (compare(other).getOrder() < 0);
     607                 :            : }
     608                 :            : 
     609                 :            : bool
     610                 :         11 : Name::gthan(const Name& other) const {
     611                 :         11 :     return (compare(other).getOrder() > 0);
     612                 :            : }
     613                 :            : 
     614                 :            : bool
     615                 :       3253 : Name::isWildcard() const {
     616 [ +  + ][ +  + ]:       3253 :     return (length_ >= 2 && ndata_[0] == 1 && ndata_[1] == '*'); 
                 [ +  + ]
     617                 :            : }
     618                 :            : 
     619                 :            : Name
     620                 :        425 : Name::concatenate(const Name& suffix) const {
     621 [ +  - ][ -  + ]:        425 :     assert(length_ > 0 && suffix.length_ > 0);
     622 [ +  - ][ -  + ]:        425 :     assert(labelcount_ > 0 && suffix.labelcount_ > 0);
     623                 :            : 
     624                 :        425 :     unsigned int length = length_ + suffix.length_ - 1;
     625         [ +  + ]:        425 :     if (length > Name::MAX_WIRE) {
     626         [ +  - ]:          6 :         isc_throw(TooLongName, "names are too long to concatenate");
     627                 :            :     }
     628                 :            : 
     629                 :          0 :     Name retname;
     630         [ +  - ]:        422 :     retname.ndata_.reserve(length);
     631         [ +  - ]:        422 :     retname.ndata_.assign(ndata_, 0, length_ - 1);
     632                 :        422 :     retname.ndata_.insert(retname.ndata_.end(),
     633         [ +  - ]:        422 :                           suffix.ndata_.begin(), suffix.ndata_.end());
     634         [ -  + ]:        422 :     assert(retname.ndata_.size() == length);
     635                 :        422 :     retname.length_ = length;
     636                 :            : 
     637                 :            :     //
     638                 :            :     // Setup the offsets vector.  Copy the offsets of this (prefix) name,
     639                 :            :     // excluding that for the trailing dot, and append the offsets of the
     640                 :            :     // suffix name with the additional offset of the length of the prefix.
     641                 :            :     //
     642                 :        422 :     unsigned int labels = labelcount_ + suffix.labelcount_ - 1;
     643         [ -  + ]:        422 :     assert(labels <= Name::MAX_LABELS);
     644         [ +  - ]:        422 :     retname.offsets_.reserve(labels);
     645                 :        844 :     retname.offsets_.assign(&offsets_[0], &offsets_[0] + labelcount_ - 1);
     646                 :            :     transform(suffix.offsets_.begin(), suffix.offsets_.end(),
     647                 :        422 :               back_inserter(retname.offsets_),
     648                 :        422 :               bind2nd(plus<char>(), length_ - 1));
     649         [ -  + ]:        422 :     assert(retname.offsets_.size() == labels);
     650                 :        422 :     retname.labelcount_ = labels;
     651                 :            : 
     652                 :        422 :     return (retname);
     653                 :            : }
     654                 :            : 
     655                 :            : Name
     656                 :       7127 : Name::reverse() const {
     657                 :          0 :     Name retname;
     658                 :            :     //
     659                 :            :     // Set up offsets: The size of the string and number of labels will
     660                 :            :     // be the same in as in the original.
     661                 :            :     //
     662         [ +  - ]:       7127 :     retname.offsets_.reserve(labelcount_);
     663         [ +  - ]:       7127 :     retname.ndata_.reserve(length_);
     664                 :            : 
     665                 :            :     // Copy the original name, label by label, from tail to head.
     666                 :       7127 :     vector<unsigned char>::const_reverse_iterator rit0 = offsets_.rbegin();
     667                 :            :     vector<unsigned char>::const_reverse_iterator rit1 = rit0 + 1;
     668                 :      14254 :     string::const_iterator n0 = ndata_.begin();
     669         [ +  - ]:       7127 :     retname.offsets_.push_back(0);
     670         [ +  + ]:      29262 :     while (rit1 != offsets_.rend()) {
     671                 :      66405 :         retname.ndata_.append(n0 + *rit1, n0 + *rit0);
     672         [ +  - ]:      22135 :         retname.offsets_.push_back(retname.ndata_.size());
     673                 :            :         ++rit0;
     674                 :            :         ++rit1;
     675                 :            :     }
     676         [ +  - ]:       7127 :     retname.ndata_.push_back(0);
     677                 :            : 
     678                 :       7127 :     retname.labelcount_ = labelcount_;
     679                 :       7127 :     retname.length_ = length_;
     680                 :            : 
     681                 :       7127 :     return (retname);
     682                 :            : }
     683                 :            : 
     684                 :            : Name
     685                 :      24522 : Name::split(const unsigned int first, const unsigned int n) const {
     686 [ +  + ][ +  + ]:      24522 :     if (n == 0 || n > labelcount_ || first > labelcount_ - n) {
                 [ +  + ]
     687         [ +  - ]:         12 :         isc_throw(OutOfRange, "Name::split: invalid split range");
     688                 :            :     }
     689                 :            : 
     690                 :          0 :     Name retname;
     691                 :            :     // If the specified range doesn't include the trailing dot, we need one
     692                 :            :     // more label for that.
     693         [ +  + ]:      24516 :     unsigned int newlabels = (first + n == labelcount_) ? n : n + 1;
     694                 :            : 
     695                 :            :     //
     696                 :            :     // Set up offsets: copy the corresponding range of the original offsets
     697                 :            :     // with subtracting an offset of the prefix length.
     698                 :            :     //
     699         [ +  - ]:      24516 :     retname.offsets_.reserve(newlabels);
     700                 :      49032 :     transform(offsets_.begin() + first, offsets_.begin() + first + newlabels,
     701                 :      24516 :               back_inserter(retname.offsets_),
     702                 :      49032 :               bind2nd(plus<char>(), -offsets_[first]));
     703                 :            : 
     704                 :            :     //
     705                 :            :     // Set up the new name.  At this point the tail of the new offsets specifies
     706                 :            :     // the position of the trailing dot, which should be equal to the length of
     707                 :            :     // the extracted portion excluding the dot.  First copy that part from the
     708                 :            :     // original name, and append the trailing dot explicitly.
     709                 :            :     //
     710         [ +  - ]:      24516 :     retname.ndata_.reserve(retname.offsets_.back() + 1);
     711                 :      49032 :     retname.ndata_.assign(ndata_, offsets_[first], retname.offsets_.back());
     712         [ +  - ]:      24516 :     retname.ndata_.push_back(0);
     713                 :            : 
     714                 :      49032 :     retname.length_ = retname.ndata_.size();
     715                 :      24516 :     retname.labelcount_ = retname.offsets_.size();
     716         [ -  + ]:      24516 :     assert(retname.labelcount_ == newlabels);
     717                 :            : 
     718                 :      24516 :     return (retname);
     719                 :            : }
     720                 :            : 
     721                 :            : Name
     722                 :       3986 : Name::split(const unsigned int level) const {
     723         [ +  + ]:       3986 :     if (level >= getLabelCount()) {
     724 [ +  - ][ +  - ]:          9 :         isc_throw(OutOfRange, "invalid level for name split (" << level
                 [ +  - ]
     725                 :            :                   << ") for name " << *this);
     726                 :            :     }
     727                 :            : 
     728                 :       3983 :     return (split(level, getLabelCount() - level));
     729                 :            : }
     730                 :            : 
     731                 :            : Name&
     732                 :        612 : Name::downcase() {
     733                 :        612 :     unsigned int nlen = length_;
     734                 :        612 :     unsigned int labels = labelcount_;
     735                 :        612 :     unsigned int pos = 0;
     736                 :            : 
     737         [ +  + ]:       2967 :     while (labels > 0 && nlen > 0) {
     738                 :       2355 :         --labels;
     739                 :       2355 :         --nlen;
     740                 :            : 
     741                 :            :         // we assume a valid name, and do abort() if the assumption fails
     742                 :            :         // rather than throwing an exception.
     743                 :       2355 :         unsigned int count = ndata_.at(pos++);
     744         [ -  + ]:       2355 :         assert(count <= MAX_LABELLEN);
     745         [ +  - ]:       2355 :         assert(nlen >= count);
     746                 :            : 
     747         [ +  + ]:      11471 :         while (count > 0) {
     748                 :       9116 :             ndata_.at(pos) =
     749                 :       9116 :                 maptolower[static_cast<unsigned char>(ndata_.at(pos))];
     750                 :       9116 :             ++pos;
     751                 :       9116 :             --nlen;
     752                 :       9116 :             --count;
     753                 :            :         }
     754                 :            :     }
     755                 :            : 
     756                 :        612 :     return (*this);
     757                 :            : }
     758                 :            : 
     759                 :            : std::ostream&
     760                 :      12436 : operator<<(std::ostream& os, const Name& name) {
     761         [ +  - ]:      12436 :     os << name.toText();
     762                 :      12436 :     return (os);
     763                 :            : }
     764                 :            : }
     765                 :      25075 : }

Generated by: LCOV version 1.9