BIND 10 #998: IP based ACL check

BIND 10 Development do-not-reply at isc.org
Thu Jun 23 07:14:01 UTC 2011


#998: IP based ACL check
-------------------------------------+-------------------------------------
                   Reporter:         |                 Owner:  jinmei
  vorner                             |                Status:  reviewing
                       Type:  task   |             Milestone:
                   Priority:  major  |  Sprint-20110628
                  Component:         |            Resolution:
  Unclassified                       |             Sensitive:  0
                   Keywords:         |           Sub-Project:  DNS
            Defect Severity:  N/A    |  Estimated Difficulty:  5.0
Feature Depending on Ticket:         |           Total Hours:  0
        Add Hours to Ticket:  0      |
                  Internal?:  0      |
-------------------------------------+-------------------------------------

Comment (by jinmei):

 Replying to [comment:21 stephen]:

 First, responding to your response.  (I have no other comments on the
 points I'm not explicitly referring to below, although there can be
 further comments on the resulting code).

 > > Do we really need the default constructor? It allows an IPCheck object
 to have a mostly invalid state, opening up a possibility of bugs.
 > Depends if it is needed.  I added the default constructor to facilitate
 its use in vectors and the like (e.g. initializing a vector of IPCheck
 objects to a known size), but it's trivial to remove it. (Note that
 compare() for an acl constructed with the default constructor will always
 return false for both IPV4 and IPV6 addresses).

 Apparently the intended usage is to use shared pointers of Check objects
 (see the ACL class merged in the master), so it's less likely to store
 bare Check objects in STL containers in practice.  In general, I'd
 prefer minimalist approach: don't introduce a feature due to a guessed
 (but yet non existent) usage.  But if you still prefer to keeping it,
 I won't oppose to it any more in this review cycle.

 > > constructor from string: inet_pton() could fail with -1, too.
 > This is only with an invalid address family

 I don't think it's guaranteed so (even though it may be the case for
 many actual implementations), but...

 > but the code now checks for the explicit success status.

 ...then that's okay (but see comments about the actual revised
 implementation below).

 > One final thing.  At present the address and comparison bitmask are both
 equal to the size of addresses of the relevant family. A possibly
 premature optimization would be to truncate them to the size dictated by
 the prefix length (e.g. is the prefix length were specified as /8, just
 store one byte).  However, this will take a little time to do and you did
 suggest that you are waiting on these changes.

 Yeah I've noticed this optimization, too.  But whether or not other
 ticket is waiting on the completion of this one, I'd rather defer this
 type of optimization to a separate ticket.

 Next, comments on the revised code.  This time I've also reviewed the
 unit tests.

 '''general'''

 You seem to have intended to apply my editorial suggestion on IPv[46]
 vs IPV[46], but the actual result seems to be different from what I
 actually suggested: my suggestion is to use "IPv4/6" (lower v) in
 comments.  You applied it in the reverse direction.  Is that
 intentional?

 I've also made a few minor changes (mostly editorial, plus constify
 something where it's trivial) and pushed them directly.

 '''acl/Makefile.am'''

 Why did you disable -Werror for libacl?

 '''splitIPAddress (revised)'''

 - prefix_size: I'd personally defer defining a mutable variable until
   we really start using it (in order to effectively limit the lifetime
   of the variable), and, in this sense, I'd move the definition of it
   immediately before this part:
 {{{
     // If there is a prefixlength, attempt to convert it.
     if (!prefixlen.empty()) {
     ...
 }}}
 - so, are we (now?) allowing beginning and ending spaces (including
   '\n')?
 - mod_prefix could (should) be const.
 - prefix could simply be initialized using the default constructor
   (which would be a bit more efficient than constructing string("") and
   coping it)
 - slashpos could (should) be const

 '''ip_check.h'''

 == general ==
 - lexical_cast.hpp and scoped_ptr.hpp should be removed

 == IPCheck ==
 - I know I may sound inconsistent regarding when to worry about
   performance and when to not, but I'm afraid using vectors are
   suboptimal in terms of both comparison performance (because its
   operator[] is slower than direct memory access) and memory footprint
   (due to the overhead of the class structure).  But this only affects
   the internal data structure and we can change this later, so I'd
   propose keeping the current implementation for now, leaving this
   discussion open and creating a separate ticket for it.
 - "any4" and "any6": I'd rather use all 0 address than keeping them
   empty because having variable length data is an easy source of bugs.
   (even though it would be less efficient in terms of memory footprint)
 - constructors: address_() and mask_() could be omitted, but this is
   probably a matter of personal taste.
 - From IPv4 constructor: I don't think it a good idea to use the host
   byte order.  And, on further thought, I'd even wonder whether we
   need these "from address" constructors in the first place for now.
   In the sense of minimalist approach, all we need for the immediate
   purpose is the constructor from the string.  While I'm hesitating to
   suggest this, maybe it'd be smoother if we backed out these
   constructors from this branch for now and defer them to a separate
   ticket.
 - From IPv4 constructor: as far as I can see we don't need static_cast
   here.
 - From string constructor: this pattern doesn't seem to be the most
   common idiom in this case:
 {{{
                 std::copy(address_bytes, address_bytes + IPV6_SIZE,
                           std::back_inserter(address_));
 }}}
   I'd rewrite this to:
 {{{
                 address_.assign(address_bytes, address_bytes + IPV6_SIZE);
 }}}
   Same comment applies to the IPv4 case.
 - From string constructor: technically this is not 100% correct:
 {{{
                     isc_throw(isc::InvalidParameter, "address prefix of "
 <<
                               ipprefix << " is a not valid");
 }}}
   (oh btw, the what message looks like a typo in "is a not valid")
   because if inet_pton fails with -1 it means a system error, not
   necessarily due to the input was invalid.  Likewise, this is also
   not entire correct:
 {{{
             } else {
                 // Not IPV6, try IPV4
 }}}
   when status == -1.  To be 100% pedantic we should do something like
   the attached diff.
 - getPrefixlen(): even though it's legal, I'd avoid shadowing the same
   name of variable 'i'.
 - getPrefixlen(): this for loop can make meaningless iterations once
   the mask byte is 0.
 - getPrefixlen(): the condition seems to be wrong.  It should be "i < 8":
 {{{
                 for (int i = 0; i < 8 * sizeof(uint8_t); ++i) {
 }}}
 - compare(): (should have noticed this before) shouldn't this be non
   virtual?
 - compare(): personally I'd list 'family' first as it seems to be more
   significant, but that's purely a matter of taste, so this is just a
   comment.

 '''ip_check_unittest'''

 - As far as I understand it, this is not correct:
 {{{
     // Check on all possible 8-bit values.  Use a signed type to generate
 a
     // variable with the most significant bits set (right-shifting will
     // introduce additional bits).
 }}}
   The behavior of >> for signed integer is implementation dependent
   (at least it is so for plain C).  To be very safe, I'd use a
   uint16_t initialized with 0xff00 with >>.  This way we could also
   integrate the case of i = 0 in the for loop.

 - Same for the 32-bit version, but I now guess we need this in the
   first place, both for the main code and test (and whether createMask
   needs to be templated) because we don't use the 32-bit version.

 - for comparison tests, I'd also use prefix lengths that are not for a
   4 or 8-bit boundary, e.g. /19, /45, /127, etc.

 - MixedMode test: I don't see a point in doing EXPECT_NO_THROW
   before EXPECT_FALSE for the same expression.  I'd either remove the
   former or change it to ASSERT_NO_THROW.

 - MixedMode test: for a more meaningful test, I'd use data that would
   confuse the compare method without the explicit family check,
   e.g. an IPv4 address to be tested and IPv6 prefix in the check whose
   first 32 bits are identical to the IPv4 address.

 '''Others'''
 These are basically random thoughts on future possible extensions.  I
 wouldn't request them be incorporated to the current branch (actually
 I'd rather defer it).

 - We might want to "normalize" the address, that is, apply the mask to
   the address.  For example, if we're given "192.0.2.1/24", internally
   convert it to "192.0.2.0/24".
 - maybe we want to implement specialized toText() for IPCheck..
 - for IPv6, we might want to support link-local addresses with scope
   consideration, i.e, differentiate fe80::1%ether0 and fe80::1%ether1.
   although not very advisable, there are actually people trying to use
   DNS over IPv6 link-local addresses.

-- 
Ticket URL: <https://bind10.isc.org/ticket/998#comment:22>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list