BIND 10 #998: IP based ACL check

BIND 10 Development do-not-reply at isc.org
Thu Jun 16 09:19:03 UTC 2011


#998: IP based ACL check
-------------------------------------+-------------------------------------
                   Reporter:         |                 Owner:  UnAssigned
  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):

 I've taken a bit more closer look at the branch, mainly for #999.

 I have some design level question/comment/suggestion.

 '''Observations'''

 First, I don't see much benefit in having both Ipv4Check and Ipv6Check
 as derived classes of IpCheck.  IpCheck is a concrete class that
 internally creates and holds IpvXCheck.  This way, applications can
 (and I guess will) only depend on IpCheck, not only when using the
 class (as in the usual usage of polymorphism) but also when creating
 it.  So IpvXCheck doesn't seem to have to be a derived class of
 IpCheck (or even a derived class of Check).

 Second, regardless of whether they are derived from IpCheck, I'm not
 so sure if it makes sense to separate classes for IPv4 and IPv6.
 Essentially they do the same thing: dealing with some binary data with
 a fixed maximum size and a variable-length effective size (in bits),
 and matching given data of the maximum size against its internal data
 (up to the effective size).  So, most of the code logic should be
 sharable, and it seems we can implement everything in a single class
 with an identifier of the address family.

 Of course, separating classes (with polymorphism) has its own
 advantages: We'll be able to benefit from stronger type checks; the
 size of the objects may be smaller (because the address family is
 embedded in the type), which can be a big plus if/when we want to a
 large number of ACL rules.  In that case, however, I'd suggest
 combining the main code logic as much as possible either via C++
 template or some design pattern techniques like template methods.

 Third: maybe this is premature at this point, but I guess Ip(vX)Check
 will need to contain the information of "which address it is", such as
 the source address or destination address.  For example, consider the
 following ACL entry:
 {{{
   allow from 2001:db8:1::/64 to 2001:db8:2::/64
 }}}
 In this case, the "Context" would be something like a "Packet" class,
 that stores the source and destination address information.  Both the
 "from 2001:db8:1::/64" and "to 2001:db8:2::/64" would be represented
 as separate Ip(v6)Check objects, and the former/latter would have to
 know it's a source/destination address; otherwise the Context cannot
 determine which address it should extract to perform the match.

 Finally: I suspect methods like "compare()" would need to take
 something more generic, at least some opaque data and the address
 family identifier.  For example, consider these rules:
 {{{
   allow from 2001:db8:1::/64 to 2001:db8:2::/64
   allow from 192.0.2.0/24 to 192.0.2.53
 }}}

 And assume that the "Packet" class is IP-version independent (just
 like our IOMessage class).  Since we'd like to keep things version
 independently as much as possible, IpCheck<Packet>::matches() would
 like to do something like this:
 {{{
     if (getAddressType() == IpCheck::SOURCE) { // see the third point
        return (compare(packet.getSourceAddr()));
    } else {
        return (compare(packet.getDestinationAddr()));
    }
 }}}

 Now, the address family of getSourceAddr() may be different from the
 IP version for this IpCheck instance, and in that case we'd be
 expected to return "false".  So, we'd like compare() to take various
 types of addresses, and return false if the family doesn't match.

 In my experimental attempt, I'm thinking about something like this:
 {{{
 struct IPAddress {
     IPAddress(const struct sockaddr& sa);
     const int family;
     const uint8_t* const data;
     const size_t length;
 }
 }}}
 with this the compare() method would take "const IPAddress&".  But
 this is just an example structure.  I'm not pushing it if there's a
 better way to implement the concept.

 '''Suggestion'''

 Considering all these, I'd suggest

 - Either make IpCheck a single "for all IP versions" check class, or
   to make IpvXCheck direct subclass of Check.  In the latter case
   IpCheck will be removed, some factory function will be introduced,
   and employ some code sharing technique (such as templates).
 - extend the compare() method (or something equivalent to that if
   addressing the first point affects this part of interface) so that
   it can take different types of addresses
 - (maybe optionally) add an interface to Ip(vX)Check to maintain and
   return the type of addresses.  The "address type" may better be
   templated (like the "Action" type of the ACL class).

 (If these suggestions are vague, I can show it via sample code)

 '''Other comments'''

 Here are some code level comments I happened to notice.

 - I'd say "IP" instead of "Ip" because "IP" is an acronym
 - I'd use unnamed namespace wherever possible in the test, and avoid
   using file-scope "static'
 - can't compare() be private?
 - "getNetmask(): const uint32_t" should be uint32_t.  The const is
   redundant, and at least clang++ actually treats it a fatal warning.

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


More information about the bind10-tickets mailing list